天天看點

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

JavaScript排坑指南(三)

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

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

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

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

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

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

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

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

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

var length = ;
function fn() {
	console.log(this.length);
}

var obj = {
  length: ,
  method: function(fn) {
    fn();
    arguments[]();
  }
};

obj.method(fn, );
複制代碼
           

output:

複制代碼
           

這個我做錯在第二個輸出上,其實對

this

了解後就知道,第一個輸出

10

應該是很顯然的:雖然在程式執行時,使用了

obj.method

方法,讓this指向了

obj

,但是真正的函數執行在函數體内部,也即當

fn()

執行的時候,

this

是指向

window

的,是以第一次執行結果是10

那麼這裡第二次執行

arguments[0]

為什麼結果是

2

分析下在

method(fn,1)

執行時,經曆了什麼: 首先兩個參數

fn

1

會被放入

arguments

中,在

arguments

中第一個參數就是我們傳入的函數;接下來

fn

執行,此時

this

沒有綁定是以指向

window

,輸出

10

。 然而到了

arguments[0]()

這一句,相當于把

arguments[0]

中的第一個參數拿來執行, 效果如下:

arguments[]()  //執行,等同于下面的
arguments() //當然這句話是不合法的,但是這樣我們可以更清楚知道,this是指向arguments執行個體本身
複制代碼
           

arguments.length

就是它本身的長度(arguments是一個類數組,具有length屬性),是以輸出

2

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

(function () {
    try {
        throw new Error();
    } catch (x) {
        var x = , y = ;
        console.log(x);
    }
    console.log(x);
    console.log(y);
})();
複制代碼
           

輸出結果:

undefined

複制代碼
           

我們都知道

var

是在預編譯階段會有一個變量提升,這種類型很容易解決,但是當遇到在

catch(x)

中與已有變量重名的情況,一定要區分兩者之間的關系。

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

(function () {
    var x,y;  // 外部變量提升
    try {
        throw new Error();
    } catch (x/* 内部的x */) {
		x = ; //内部的x,和上面聲明的x不是一回事!!
         y = ; //内部沒有聲明,作用域鍊向上找,外面的y
        console.log(x); //當然是1
    }
    console.log(x);  //隻聲明,未指派,undefined
    console.log(y);  //就是2了
})();
複制代碼
           

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

Q3. 下面程式的輸出

var x = ;
var girl = function () {
    console.log(x);
    var x = ;
};
girl ();
複制代碼
           

輸出:

undefined
複制代碼
           

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

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

var x = ;
var girl = function() {
    var x;
    console.log(x); // undefined
    x = ;
}
}
複制代碼
           

那些詭異的邊角知識

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

console.log( <  < );
console.log( >  > );
複制代碼
           

輸出:

true
flase
複制代碼
           

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

false

核心在于js怎麼去解析

<

>

運算符。 在JS中,這種運算符是從左向右運算的,是以

3>2>1

就被轉換成了

true>1

,而

true

的值是

1

,接着比較

1>1

就傳回false了。

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

console.log(typeof typeof );
複制代碼
           

答案是

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對大小寫敏感,

null

NULL

,是以``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); //遞歸
    })
}
複制代碼
           

繼續閱讀