前端面試&筆試&錯題指南(三)

Vincent Ko發表於2018-08-11

JavaScript排坑指南(三)

JavaScript總是給人以驚喜,學習不止,進步不斷,今天繼續補充JS容易搞錯的幾道筆試/面試題,為了秋招繼續努力,歡迎一起為秋招努力的小夥伴共勉

--------------------------------------總部傳送門-----------------------------------

1.VK的秋招前端奇遇記(一)

2.VK的秋招前端奇遇記(二)

3.VK的秋招前端奇遇記(三)

4.VK的秋招前端奇遇記(四)

5.番外篇:前端面試&筆試演算法 Algorithm

”老生常錯“的this與作用域相關

Q1. 下面程式的輸出結果是?

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應該是很顯然的:雖然在程式執行時,使用了obj.method方法,讓this指向了obj,但是真正的函式執行在函式體內部,也即當fn()執行的時候,this是指向window的,所以第一次執行結果是10

那麼這裡第二次執行arguments[0]為什麼結果是2

分析下在method(fn,1)執行時,經歷了什麼: 首先兩個引數fn1會被放入arguments中,在arguments中第一個引數就是我們傳入的函式;接下來fn執行,此時this沒有繫結因此指向window,輸出10。 然而到了arguments[0]()這一句,相當於把arguments[0]中的第一個引數拿來執行, 效果如下:

arguments[0]()  //執行,等同於下面的
arguments.0() //當然這句話是不合法的,但是這樣我們可以更清楚知道,this是指向arguments例項本身
複製程式碼

arguments.length就是它本身的長度(arguments是一個類陣列,具有length屬性),因此輸出2


Q2. try..catch程式的輸出結果

(function () {
    try {
        throw new Error();
    } catch (x) {
        var x = 1, y = 2;
        console.log(x);
    }
    console.log(x);
    console.log(y);
})();
複製程式碼

輸出結果:

1
undefined
2
複製程式碼

我們都知道var是在預編譯階段會有一個變數提升,這種型別很容易解決,但是當遇到在catch(x)中與已有變數重名的情況,一定要區分兩者之間的關係。

用變數提升的方法,把程式重寫並分析如下:

(function () {
    var x,y;  // 外部變數提升
    try {
        throw new Error();
    } catch (x/* 內部的x */) {
		x = 1; //內部的x,和上面宣告的x不是一回事!!
         y = 2; //內部沒有宣告,作用域鏈向上找,外面的y
        console.log(x); //當然是1
    }
    console.log(x);  //只宣告,未賦值,undefined
    console.log(y);  //就是2了
})();
複製程式碼

這樣子就很清晰,之後注意預編譯的過程,把變數和函式定義進行提升後,進行分析,會清楚很多


Q3. 下面程式的輸出

var x = 21;
var girl = function () {
    console.log(x);
    var x = 20;
};
girl ();
複製程式碼

輸出:

undefined
複製程式碼

說實話,這個題目我沒做錯,我沒做錯,我沒做錯!

因為和Q2一樣,而且還沒有Q2難,一句話解釋就是: 函式內部變數提升。 相當於

var x = 21;
var girl = function() {
    var x;
    console.log(x); // undefined
    x = 20;
}
}
複製程式碼

那些詭異的邊角知識

Q1. 運算子考點: 下面程式輸出是什麼?

console.log(1 < 2 < 3);
console.log(3 > 2 > 1);
複製程式碼

輸出:

true
flase
複製程式碼

第一個輸出結果是好理解的,主要看下第二個為什麼是false

核心在於js怎麼去解析<>運算子。 在JS中,這種運算子是從左向右運算的,所以3>2>1就被轉換成了true>1,而true的值是1,接著比較1>1就返回false了。


Q2. typeof,下面輸出結果是什麼

console.log(typeof typeof 1);
複製程式碼

答案是string

會輸出string,這個題目不僅僅是typeof的考察,也是對js運算的一個考察。 在js中一般有兩種操作

  • 賦值操作,例如a = b 2>3之類的,上面的題目提到過,是從左向右的順序
  • 取值操作, js問記憶體:有沒有見過這個傢伙?,比如console.log(a) typeof a 都屬於這個型別,是從右向左的

因此,這個題就被分解為typeof 1返回"number",注意是一個字串。 接下來typeof "number",返回string


Q3. typeof undefined == typeof NULL輸出結果是什麼

首先搞清楚兩點:

  • typeof undefined 輸出是undefined
  • typeof null輸出是object

但是,另一方面,因為js對大小寫敏感,nullNULL,所以``typeof NULL返回undefined`

結果是: true

Q4. 遞迴設計。 實現一個函式,給該函式一個DOM節點,函式訪問其所有子元素(所有子元素,不僅僅是直接子元素),每次訪問子元素的時候,併為其傳一個callback。

訪問一個DOM tree,是一個經典的深度優先搜尋的演算法

function Traverse(DOM,callback) {
    callback(DOM);
    var list = DOM.children;
    Array.prototype.forEach.apply(list,(item)=>{
        Traverse(item,callback); //遞迴
    })
}
複製程式碼

相關文章