主流公司的21個JavaScript面試問題
21個基本JavaScript面試問題
問題1
1. undefined
和not defined在
JavaScript中有什麼區別?
在JavaScript中,如果您嘗試使用不存在且尚未宣告的變數,則JavaScript將引發錯誤var name is not defined
並且指令碼將停止執行。但是,如果你使用typeof undeclared_variable
,那麼它將返回undefined
。
在進一步討論之前,讓我們先了解宣告和定義之間的區別。
假設var x
是一個宣告,因為你還沒有定義它所擁有的值,但你已經聲明瞭它的存在以及記憶體分配的需要。
> var x; // declaring x > console.log(x); //output: undefined
這var x = 1
是一個宣告和定義(我們也可以說我們正在進行初始化)。在上面的示例中,值的宣告和賦值發生在變數x的內聯中。在JavaScript中,呼叫您帶到當前範圍頂部的每個變數或函式宣告hoisting
。
賦值按順序發生,因此當我們嘗試訪問已宣告但尚未定義的變數時,我們將得到結果undefined
。
var x; // Declaration
if(typeof x === 'undefined') // Will return true
如果一個既未宣告也未定義的變數,當我們嘗試引用這樣的變數時,我們會得到結果not defined
。
> console.log(y); // Output: ReferenceError: y is not defined
問題2
下面程式碼的輸出是什麼?
var y = 1;
if (function f(){}) {
y += typeof f;
}
console.log(y);
輸出將是1undefined
。該if
條件語句計算使用eval
,所以eval(function f(){})
回報率function f(){}
(這是真的)。因此,在if
語句內部,由於語句程式碼在執行時執行,因此執行typeof f
返回,並且在執行時評估條件內的語句。undefined
if
if
var k = 1; if (1) { eval(function foo(){}); k += typeof foo; } console.log(k);
上面的程式碼也會輸出1undefined
。
var k = 1;
if (1) {
function foo(){};
k += typeof foo;
}
console.log(k); // output 1function
問題3
在JavaScript中建立真正的私有方法有什麼缺點?
在JavaScript中建立真正的私有方法的一個缺點是它們的記憶體效率非常低,因為將為每個例項建立該方法的新副本。
var Employee = function (name, company, salary) {
this.name = name || ""; //Public attribute default value is null
this.company = company || ""; //Public attribute default value is null
this.salary = salary || 5000; //Public attribute default value is null
// Private method
var increaseSalary = function () {
this.salary = this.salary + 1000;
};
// Public method
this.dispalyIncreasedSalary = function() {
increaseSlary();
console.log(this.salary);
};
};
// Create Employee class object
var emp1 = new Employee("John","Pluto",3000);
// Create Employee class object
var emp2 = new Employee("Merry","Pluto",2000);
// Create Employee class object
var emp3 = new Employee("Ren","Pluto",2500);
這裡的每個例項變數emp1
,emp2
,emp3
有其自身的副本increaseSalary
私有方法。
因此,作為建議,除非必要,否則不要使用私有方法。
問題4
什麼是JavaScript中的“閉包”?舉個例子
閉包是在另一個函式(稱為父函式)中定義的函式,並且可以訪問在父函式作用域中宣告和定義的變數。
閉包可以訪問三個範圍中的變數:
- 在自己的範圍內宣告的變數
- 在父函式範圍中宣告的變數
- 在全域性名稱空間中宣告的變數
var globalVar = "abc";
// Parent self invoking function
(function outerFunction (outerArg) { // begin of scope outerFunction
// Variable declared in outerFunction function scope
var outerFuncVar = 'x';
// Closure self-invoking function
(function innerFunction (innerArg) { // begin of scope innerFunction
// variable declared in innerFunction function scope
var innerFuncVar = "y";
console.log(
"outerArg = " + outerArg + "\n" +
"outerFuncVar = " + outerFuncVar + "\n" +
"innerArg = " + innerArg + "\n" +
"innerFuncVar = " + innerFuncVar + "\n" +
"globalVar = " + globalVar);
}// end of scope innerFunction)(5); // Pass 5 as parameter
}// end of scope outerFunction )(7); // Pass 7 as parameter
innerFunction
是在內部定義的閉包,outerFunction
並且可以訪問在outerFunction
作用域中宣告和定義的所有變數。另外,在另一個函式中定義的函式作為閉包將有權訪問在中宣告的變數global namespace
。
因此,上面程式碼的輸出將是:
outerArg = 7
outerFuncVar = x
innerArg = 5
innerFuncVar = y
globalVar = abc
問題5
編寫一個mul
函式,在呼叫時將產生以下輸出:
console.log(mul(2)(3)(4)); // output : 24
console.log(mul(4)(3)(4)); // output : 48
下面是答案,然後解釋它是如何工作的:
function mul (x) {
return function (y) { // anonymous function
return function (z) { // anonymous function
return x * y * z;
};
};
}
這裡mul
函式接受第一個引數並返回一個匿名函式,它接受第二個引數並返回另一個匿名函式,該函式將獲取第三個引數並返回已傳遞的引數的乘法。
在JavaScript中,在另一個函式內定義的函式可以訪問外部函式的變數。因此,函式是一個第一類物件,也可以由其他函式返回,並作為引數傳遞給另一個函式。
- 函式是Object型別的例項
- 函式可以具有屬性,並具有返回其建構函式方法的連結
- 函式可以儲存為變數
- 函式可以作為引數傳遞給另一個函式
- 可以從另一個函式返回一個函式
問題6
如何在JavaScript中清空陣列?
例如,
var arrayList = ['a','b','c','d','e','f'];
我們怎樣才能清空上面的陣列?
我們可以使用幾種方法來清空陣列,所以讓我們討論它們。
方法1
arrayList = []
上面的程式碼將變數設定arrayList
為一個新的空陣列。如果您在其他任何地方都沒有對原始陣列的引用, 則建議使用此方法arrayList
,因為它實際上會建立一個新的空陣列。您應該小心這種清空陣列的方法,因為如果您從另一個變數引用了這個陣列,那麼原始引用陣列將保持不變。
例如,
var arrayList = ['a','b','c','d','e','f']; // Created array
var anotherArrayList = arrayList; // Referenced arrayList by another variable
arrayList = []; // Empty the array
console.log(anotherArrayList); // Output ['a','b','c','d','e','f']
方法2
arrayList.length = 0;
上面的程式碼將通過將其長度設定為0來清除現有陣列。這種清空陣列的方式還會更新指向原始陣列的所有引用變數。因此,當您想要更新指向的所有引用變數時,此方法很有用arrayList
。
例如,
var arrayList = ['a','b','c','d','e','f']; // Created array
var anotherArrayList = arrayList; // Referenced arrayList by another variable
arrayList.length = 0; // Empty the array by setting length to 0
console.log(anotherArrayList); // Output []
方法3
arrayList.splice(0, arrayList.length);
上面的實現也將完美地運作。這種清空陣列的方法也將更新對原始陣列的所有引用。
var arrayList = ['a','b','c','d','e','f']; // Created array
var anotherArrayList = arrayList; // Referenced arrayList by another variable
arrayList.splice(0, arrayList.length); // Empty the array by setting length to 0
console.log(anotherArrayList); // Output []
方法4
while(arrayList.length){
arrayList.pop();
}
上面的實現也可以清空陣列,但通常不建議經常使用此方法。
問題7
如何檢查物件是否是陣列?
找出物件是否是特定類的例項的最佳方法是使用以下toString
方法Object.prototype
:
var arrayList = [1,2,3];
型別檢查物件的最佳用例之一是我們在JavaScript中進行方法過載。例如,假設我們有一個名為的方法greet
,它接受一個字串和一個字串列表。為了使我們的greet方法在兩種情況下都可行,我們需要知道傳遞的引數型別。它是單個值還是值列表?
function greet(param){
if(){ // here have to check whether param is array or not
}else{
}
}
但是,由於上面的實現可能不一定檢查陣列的型別,我們可以檢查單個值字串並在else塊中放入一些陣列邏輯程式碼。例如:
function greet(param){
if(typeof param === 'string'){
}else{
// If param is of type array then this block of code would execute
}
}
現在它的罰款,我們可與上述兩種實現去,但是當我們遇到這樣的情況該引數可以是single value
,array
和object
型別,我們就會有麻煩。
回到檢查物件的型別,如前所述,我們可以使用Object.prototype.toString
if( Object.prototype.toString.call( arrayList ) === '[object Array]' ) {
console.log('Array!');
}
如果您正在使用jQuery
,那麼您也可以使用jQuery isArray
方法:
if($.isArray(arrayList)){
console.log('Array');
}else{
console.log('Not an array');
}
僅供參考,jQuery在Object.prototype.toString.call
內部使用來檢查物件是否是陣列。
在現代瀏覽器中,您也可以使用
Array.isArray(arrayList);
Array.isArray
Chrome 5,Firefox 4.0,IE 9,Opera 10.5和Safari 5支援
問題8
以下程式碼的輸出是什麼?
var output = (function(x){
delete x;
return x;
})(0);
console.log(output);
輸出將是0
。的delete
運算子用於從物件中刪除屬性。這x
不是一個物件,而是一個區域性變數。delete
運算子不會影響區域性變數。
問題9
以下程式碼的輸出是什麼?
var x = 1;
var output = (function(){
delete x;
return x;
})();
console.log(output);
輸出將是1
。該delete
操作是用來刪除物件的屬性。這x
不是一個物件,而是它的全域性變數型別number
。
問題10
下面程式碼的輸出是什麼?
var x = { foo : 1};
var output = (function(){
delete x.foo;
return x.foo;
})();
console.log(output);
輸出將是undefined
。該delete
操作是用來刪除物件的屬性。這裡,x
是一個具有屬性的物件foo
,因為它是一個自呼叫函式,我們foo
將從物件中刪除該屬性x
。在這樣做之後,當我們嘗試引用已刪除的屬性時foo
,結果是undefined
。
問題11
下面程式碼的輸出是什麼?
var Employee = {
company: 'xyz'
}
var emp1 = Object.create(Employee);
delete emp1.company
console.log(emp1.company);
輸出將是xyz
。在這裡,emp1
物件都有company
其原型屬性。該delete
操作不會刪除原型屬性。
emp1
物件沒有公司作為自己的財產。你可以測試一下console.log(emp1.hasOwnProperty('company')); //output : false
。但是,我們可以company
直接從Employee
物件中刪除屬性delete Employee.company
。或者,我們也可以emp1
使用__proto__
屬性刪除物件delete emp1.__proto__.company
。
問題12
什麼是undefined x 1
JavaScript?
var trees = ["redwood","bay","cedar","oak","maple"];
delete trees[3];
當您執行上面的程式碼並輸入console.log(trees);
Chrome開發者控制檯時,您將獲得["redwood", "bay", "cedar", undefined × 1, "maple"]
。當您在Firefox的瀏覽器控制檯中執行程式碼時,您將獲得["redwood", "bay", "cedar", undefined, "maple"]
。因此,很明顯Chrome瀏覽器有自己的方式在陣列中顯示未初始化的索引。但是,當您同時檢trees[3] === undefined
入兩個瀏覽器時,您將得到類似的輸出true
。
注意:請記住,您不需要檢查陣列的未初始化索引 trees[3] === 'undefined × 1'
,因為它會給您一個錯誤。'undefined × 1'
只是在Chrome中顯示陣列未初始化索引的方法。
問題13
下面程式碼的輸出是什麼?
var trees = ["xyz","xxxx","test","ryan","apple"];
delete trees[3];
console.log(trees.length);
輸出將是5
。當我們使用delete
運算子刪除陣列元素時,陣列長度不受此影響。即使您使用delete
運算子刪除了陣列的所有元素,這也成立。
換句話說,當delete
運算子刪除陣列元素時,該陣列中不再存在該已刪除元素。代替值在刪除的索引undefined x 1
在鉻和undefined
被放置在索引處。如果您在Chrome和Firefox中console.log(trees)
輸出。["xyz", "xxxx", "test", undefined × 1, "apple"]
["xyz", "xxxx", "test", undefined, "apple"]
問題14
下面程式碼的輸出是什麼?
var bar = true;
console.log(bar + 0);
console.log(bar + "xyz");
console.log(bar + true);
console.log(bar + false);
程式碼將輸出1, "truexyz", 2, 1
。以下是新增運算子的一般準則:
- 數字+數字 - >加法
- 布林+數字 - >加法
- 布林+數字 - >加法
- 數字+字串 - >連線
- String + Boolean - > Concatenation
- String + String - > Concatenation
問題15
下面程式碼的輸出是什麼?
var z = 1, y = z = typeof y;
console.log(y);
輸出將是undefined
。根據associativity
規則,具有相同優先順序的運算子基於運算子的關聯屬性進行處理。在這裡,賦值運算子的結合性Right to Left
,所以typeof y
會先評估,這是undefined
。它將被分配給z
,然後y
將被賦值為z,然後z
將賦值1
。
問題16
下面程式碼的輸出是什麼?
// NFE (Named Function Expression
var foo = function bar(){ return 12; };
typeof bar();
輸出將是Reference Error
。要使上面的程式碼工作,您可以按如下方式重寫它:
樣品1
var bar = function(){ return 12; };
typeof bar();
要麼
樣本2
function bar(){ return 12; };
typeof bar();
函式定義只能有一個引用變數作為其函式名。在示例1中,bar
的引用變數指向anonymous function
。在示例2中,函式的定義是名稱函式。
var foo = function bar(){
// foo is visible here
// bar is visible here
console.log(typeof bar()); // Work here :)
};
// foo is visible here
// bar is undefined here
問題17
下面的函式宣告有什麼區別?
var foo = function(){
// Some code
};
function bar(){
// Some code
};
主要區別在於foo
定義了函式,run-time
而函式bar
是在解析時定義的。為了更好地理解這一點,讓我們看看下面的程式碼:
Run-Time function declaration
<script>
foo(); // Calling foo function here will give an Error
var foo = function(){
console.log("Hi I am inside Foo");
};
</script>
<script>
Parse-Time function declaration
bar(); // Calling foo function will not give an Error
function bar(){
console.log("Hi I am inside Foo");
};
</script>
這種第一種宣告方式的另一個優點是您可以根據特定條件宣告函式。例如:
<script>
if(testCondition) {// If testCondition is true then
var foo = function(){
console.log("inside Foo with testCondition True value");
};
}else{
var foo = function(){
console.log("inside Foo with testCondition false value");
};
}
</script>
但是,如果您嘗試使用以下格式執行類似的程式碼,則會出現錯誤:
<script>
if(testCondition) {// If testCondition is true then
function foo(){
console.log("inside Foo with testCondition True value");
};
}else{
function foo(){
console.log("inside Foo with testCondition false value");
};
}
</script>
問題18
什麼是JavaScript中的函式提升?
功能表達
var foo = function foo(){
return 12;
};
在JavaScript中,變數和函式是hoisted
。讓我們hoisting
先把功能。基本上,JavaScript直譯器會向前查詢所有變數宣告,然後將它們提升到宣告它們的函式的頂部。例如:
foo(); // Here foo is still undefined
var foo = function foo(){
return 12;
};
在上面的程式碼的場景後面看起來像這樣:
var foo = undefined;
foo(); // Here foo is undefined
foo = function foo(){
/ Some code stuff
}
var foo = undefined;
foo = function foo(){
/ Some code stuff
}
foo(); // Now foo is defined here
問題19
下面的程式碼輸出是什麼?
var salary = "1000$";
(function () {
console.log("Original salary was " + salary);
var salary = "5000$";
console.log("My New Salary " + salary);
})();
輸出將是undefined, 5000$
。新手常常被JavaScript的提升概念所欺騙。在上面的程式碼中,您可能希望salary
從外部作用域保留其值,直到salary
在內部作用域中重新宣告的點。但是,由於hoisting
,工資價值是undefined
相反的。要更好地理解這一點,請檢視以下程式碼:
var salary = "1000$";
(function () {
var salary = undefined;
console.log("Original salary was " + salary);
salary = "5000$";
console.log("My New Salary " + salary);
})();
salary
變數在函式範圍的頂部被提升並宣告。該console.log
內部回報率undefined
。之後console.log
,salary
重新申報並分配5000$
。
問題20
instanceof
JavaScript中的運算子是什麼?下面程式碼的輸出是什麼?
function foo(){
return foo;
}
new foo() instanceof foo;
這裡,instanceof
運算子檢查當前物件,如果物件是指定型別,則返回true。
例如:
var dog = new Animal();
dog instanceof Animal // Output : true
這dog instanceof Animal
是真的,因為dog
繼承自Animal.prototype
。
var name = new String("xyz");
name instanceof String // Output : true
這name instanceof String
是真的,因為dog
繼承自String.prototype
。現在讓我們理解下面的程式碼:
function foo(){
return foo;
}
new foo() instanceof foo;
這裡函式foo
返回foo
,再次指向函式foo
。
function foo(){
return foo;
}
var bar = new foo();
// here bar is pointer to function foo(){return foo}.
所以new foo() instanceof foo
迴歸false
;
問題21
如果我們有一個JavaScript關聯陣列
var counterArray = {
A : 3,
B : 4
};
counterArray["C"] = 1;
我們如何計算上述關聯陣列的長度counterArray
?
此處沒有可用於計算關聯陣列物件長度的內建函式和屬性。但是,我們可以通過其他方式計算關聯陣列物件的長度。除此之外,我們還可以Object
通過向原型新增方法或屬性來擴充套件,以便計算長度。但是,擴充套件物件可能會破壞各種庫中的列舉,或者可能會產生跨瀏覽器問題,因此除非必要,否則不建議使用它。同樣,我們可以通過各種方式計算長度。
Object
有keys
可用於計算物件長度的方法:
We can also calculate the length of an object by iterating through an object and by counting the object's own property.
```javascript
function getSize(object){
var count = 0;
for(key in object){
// hasOwnProperty method check own property of object
if(object.hasOwnProperty(key)) count++;
}
return count;
}
我們還可以length
直接新增方法Object
:
Object.length = function(){
var count = 0;
for(key in object){
// hasOwnProperty method check own property of object
if(object.hasOwnProperty(key)) count++;
}
return count;
}
//Get the size of any object using
console.log(Object.length(counterArray))
另外的方式:我們也可以使用Underscore
(推薦,因為它的重量輕)來計算物件長度。
本文翻譯自:點選訪問