5道BAT大廠面試題,助你夯實js基礎
技術標籤:面試總結javascript
前言:
最近看到了一篇大廠面試題集錦,在這裡摘出來一些比較有意思的面試題跟大家分享,通過這些試題的分析,加深大家對js的理解,夯實基礎知識。
1.輸出以下程式碼的執行結果
var obj = {
'2': 3,
'3': 4,
'length': 2,
'splice': Array.prototype.splice,
'push': Array.prototype.push
}
obj.push(1);
obj.push(2);
console.log(obj);
考察點1:
對push的理解,push
是根據length
我們來去除其他程式碼,僅保留push
來看看控制檯輸出
var obj = {
'2': 3,
'3': 4,
'length': 2,
// 'splice': Array.prototype.splice,
'push': Array.prototype.push
}
obj.push(1);
obj.push(2);
console.log(obj);
輸出:
{2: 1, 3: 2, length: 4, push: ƒ}
可以看到因為length
為2,所以push
是從下標為2的地方開始插入,下標為2跟3的值被push
進去的值覆蓋。
接下來我們修改length
var obj = {
'2': 3,
'3': 4,
'length': 0,
// 'splice': Array.prototype.splice,
'push': Array.prototype.push
}
obj.push(1);
obj.push(2);
console.log(obj);
輸出:
{0: 1, 1: 2, 2: 3, 3: 4, length: 2, push: ƒ}
可以看到如果length
改為0,那麼push是從0開始插入
考察點2:
當一個物件擁有splice
函式作為屬性時,控制檯會以陣列形式輸出
var obj = { '2': 3, '3': 4, 'length': 2, 'splice': Array.prototype.splice, 'push': Array.prototype.push } obj.push(1); obj.push(2); console.log(obj); 輸出: [empty × 2, 1, 2, splice: ƒ, push: ƒ]
雖然控制檯輸出的是陣列形式,但是obj依然是物件型別
var obj = {
'2': 3,
'3': 4,
'length': 2,
'splice': Array.prototype.splice,
'push': Array.prototype.push
}
obj.push(1);
obj.push(2);
console.log(obj);
console.log(obj instanceof Array)
console.log(obj instanceof Object)
輸出:
[empty × 2, 1, 2, splice: ƒ, push: ƒ]
false
true
結合兩個考察點,我們可以分析出最終結果
[empty × 2, 1, 2, splice: ƒ, push: ƒ]
2.輸出以下程式碼的執行結果
var a = {n:1};
var b = a;
a.x = a = {n:2};
console.log(a.x);
console.log(b.x);
考察點1:
連續賦值,順序從右向左。
考察點2:
運算子優先順序,點的優先順序要高於等號。更多運算子優先順序請參閱運算子優先順序
考察點3
引用資料型別的值是指向堆的指標。
我們先看輸出
undefined
{n: 2}
解析:
var a = {n:1};
var b = a; //將b指向{n:1}
a.x = a = {n:2};
// 1. a.x 會在{n:1,x:undefined}
// 2. 將a重新指向{n:2}
// 3. 將{n:1,x:undefined}中的x指向{n:2}
// 4. 此時 b: {n:1,x:{n:2}}, a: {n:2}
console.log(a.x);
console.log(b.x);
3.輸出以下程式碼的執行結果
var a = 10;
(function(){
console.log(a);
a=5;
console.log(window.a);
var a = 20;
console.log(a)
})()
考察點1:
變數提升,es6之前只存在全域性作用域跟函式作用域,變數提升就是將變數定義提升到當前作用域的開始。
考察點2:
作用域,es6之前只存在全域性作用域跟函式作用域,當賦值變數或者查詢變數時,會現在當前作用域查詢,如果沒有找到會向上級作用域查詢,直到找到全域性作用域。
解析:
var a = 10;
(function(){
console.log(a);
a=5;
console.log(window.a);
var a = 20;
console.log(a)
})()
結果:
undefined 10 20
// 1. 立即執行函式內的 var a = 20; 會先進行變數提升。 var a = undefined;會提升到函式作用域頂部
// 2. 這時候console.log(a) 的a為undefined
// 3. console.log(window.a),這時候取的是window的a變數,這時候全域性物件下的a變數為10
// 4. 執行到var a = 20; 這時候會在當前作用域查詢a變數,找到了以後賦值為20
// 5. 這時候輸出console.log(a) 這時候a的值為20
4.下面程式碼中a在什麼情況下會列印1?
var a = ?;
if(a == 1 && a == 2 && a == 3){
console.log(1);
}
考察點1:
隱式型別轉換,當進行±等運算或者==時,會進行隱式型別轉換。
考察點2:
物件轉為原始型別時會先呼叫自身valueOf方法,如果沒有返回原始值,會繼續呼叫自身的toString方法,如果還是沒有返回原始型別,則丟擲異常。
var a = {
i:1,
toString:function(){
console.log('toString',this.i)
return this.i++
},
valueOf:function(){
console.log('valueOf',this.i)
return this.i++
}
};
if(a == 1 && a == 2 && a == 3){
console.log(1);
}
輸出:
valueOf 1
valueOf 2
valueOf 3
1
// 1. a為一個物件,在轉換為數字時會呼叫valueOf
// 2. valueOf執行完畢以後再次轉換時會繼續呼叫valueOf
// 3. 當()內的表示式執行完畢後a內的i變為4
5.輸出以下程式碼的執行結果
var b = 10;
(function b(){
b=20;
console.log(b)
})()
console.log(b)
考察點1:
立即執行表示式會生成一個區域性作用域,起到隔離引數的作用。
考察點2:
函式提升要高於變數提升
例子:
var a = 1;
function a(){
}
console.log(a)
輸出:
1
由此可見,函式的優先順序要高於var變數定義。
考察點3:
具名函式表示式只能由內部訪問,並且具名函式表示式的name無法重新賦值
舉個例子:
var a = function b(){
console.log(b);
b=1;
console.log();
}
輸出:
ƒ b(){
console.log(b);
b=1;
console.log(b)
}
ƒ b(){
console.log(b);
b=1;
console.log(b)
}
解析:
var b = 10;
(function b(){
b=20;
console.log(b)
})()
console.log(b)
輸出:
ƒ b(){
b=20;
console.log(b)
}
10
// 1. 立即執行函式有兩種定義方式
(1). (function(){})()
(2). (function(){}())
(3). !、,、+、-等符號 !function(){}()
// 2. 當函式被()包裹以後,這個函式就不是函式聲明瞭,就變成了一個函式表示式
// 3. 具名函式表示式內部的b無法重新定義,所以輸出的是b函式
// 4. b=20 賦值查詢當前作用域,查到了具名函式表示式的name,但是無法重新賦值,查詢到了不再繼續向上查詢
// 4. 最後的console輸出的是全域性變數b,所以是10
如果想獲取更多內容,可以掃描下方二維碼,一起學習,一起進步。