那些年,幾道”老生常錯“的前端面試題
”老生常錯“的this與作用域相關(guān)
Q1. 下面程序的輸出結(jié)果是?
var?length?=?10;
function?fn()?{
?console.log(this.length);
}
var?obj?=?{
??length:?5,
??method:?function(fn)?{
????fn();
????arguments[0]();
??}
};
obj.method(fn,?1);
output:
10
2
這個我做錯在第二個輸出上,其實對this了解后就知道,第一個輸出10應(yīng)該是很顯然的:雖然在程序執(zhí)行時,使用了obj.method方法,讓this指向了obj,但是真正的函數(shù)執(zhí)行在函數(shù)體內(nèi)部,也即當(dāng)fn()執(zhí)行的時候,this是指向window的,所以第一次執(zhí)行結(jié)果是10
那么這里第二次執(zhí)行arguments[0]為什么結(jié)果是2?
分析下在method(fn,1)執(zhí)行時,經(jīng)歷了什么:首先兩個參數(shù)fn和1會被放入arguments中,在arguments中第一個參數(shù)就是我們傳入的函數(shù);接下來fn執(zhí)行,此時this沒有綁定因此指向window,輸出10。然而到了arguments0這一句,相當(dāng)于把a(bǔ)rguments[0]中的第一個參數(shù)拿來執(zhí)行, 效果如下:
arguments[0]()??//執(zhí)行,等同于下面的
arguments.0()?//當(dāng)然這句話是不合法的,但是這樣我們可以更清楚知道,this是指向arguments實例本身
arguments.length就是它本身的長度(arguments是一個類數(shù)組,具有l(wèi)ength屬性),因此輸出2
Q2. try..catch程序的輸出結(jié)果
(function?()?{
????try?{
????????throw?new?Error();
????}?catch?(x)?{
????????var?x?=?1,?y?=?2;
????????console.log(x);
????}
????console.log(x);
????console.log(y);
})();
輸出結(jié)果:
1
undefined
2
我們都知道var是在預(yù)編譯階段會有一個變量提升,這種類型很容易解決,但是當(dāng)遇到在catch(x)中與已有變量重名的情況,一定要區(qū)分兩者之間的關(guān)系。
用變量提升的方法,把程序重寫并分析如下:
(function?()?{
????var?x,y;??//?外部變量提升
????try?{
????????throw?new?Error();
????}?catch?(x/*?內(nèi)部的x?*/)?{
??x?=?1;?//內(nèi)部的x,和上面聲明的x不是一回事??!
?????????y?=?2;?//內(nèi)部沒有聲明,作用域鏈向上找,外面的y
????????console.log(x);?//當(dāng)然是1
????}
????console.log(x);??//只聲明,未賦值,undefined
????console.log(y);??//就是2了
})();
這樣子就很清晰,之后注意預(yù)編譯的過程,把變量和函數(shù)定義進(jìn)行提升后,進(jìn)行分析,會清楚很多
Q3. 下面程序的輸出
var?x?=?21;
var?girl?=?function?()?{
????console.log(x);
????var?x?=?20;
};
girl?();
輸出:
undefined
說實話,這個題目我沒做錯,我沒做錯,我沒做錯!
因為和Q2一樣,而且還沒有Q2難,一句話解釋就是:函數(shù)內(nèi)部變量提升。相當(dāng)于
var?x?=?21;
var?girl?=?function()?{
????var?x;
????console.log(x);?//?undefined
????x?=?20;
}
}
那些詭異的邊角知識 Q1. ?運(yùn)算符考點:下面程序輸出是什么?
console.log(1?2?3);
console.log(3?>?2?>?1);
輸出:
true
flase
第一個輸出結(jié)果是好理解的,主要看下第二個為什么是false
核心在于js怎么去解析<和>運(yùn)算符。在JS中,這種運(yùn)算符是從左向右運(yùn)算的,所以3>2>1就被轉(zhuǎn)換成了true>1,而true的值是1,接著比較1>1就返回false了。
Q2. typeof,下面輸出結(jié)果是什么
console.log(typeof?typeof?1);
答案是string
會輸出string,這個題目不僅僅是typeof的考察,也是對js運(yùn)算的一個考察。在js中一般有兩種操作
賦值操作,例如a = b 2>3之類的,上面的題目提到過,是從左向右的順序
取值操作, js問內(nèi)存:有沒有見過這個家伙?,比如console.log(a) typeof a 都屬于這個類型,是從右向左的
因此,這個題就被分解為typeof 1返回"number",注意是一個字符串。接下來typeof "number",返回string
Q3. typeof undefined == typeof NULL輸出結(jié)果是什么
首先搞清楚兩點:
typeof undefined 輸出是undefined
typeof null輸出是object
但是,另一方面,因為js對大小寫敏感,null ≠ NULL,所以typeof NULL返回undefined結(jié)果是:true
Q4. 遞歸設(shè)計。實現(xiàn)一個函數(shù),給該函數(shù)一個DOM節(jié)點,函數(shù)訪問其所有子元素(所有子元素,不僅僅是直接子元素),每次訪問子元素的時候,并為其傳一個callback。
訪問一個DOM tree,是一個經(jīng)典的深度優(yōu)先搜索的算法
function?Traverse(DOM,callback)?{
????callback(DOM);
????var?list?=?DOM.children;
????Array.prototype.forEach.apply(list,(item)=>{
????????Traverse(item,callback);?//遞歸
????})
}
原文:https://juejin.cn/post/6844903655041138702

