动态

详情 返回 返回

煩人的this,7個關於js關鍵詞的面試題 - 动态 详情

更多文章詳見公眾號【前端css和js乾貨】

在 JavaScript 中,this是函數的調用上下文。
難度在於this具有複雜的行為。
本文,整理了一個關於this關鍵字的7個有趣面試問題的列表。
注意:下面的 JavaScript 片段在非嚴格模式下運行,也稱為 sloppy 模式。

1: 變量 vs 屬性

以下代碼會在控制枱打印什麼:

const object = {

message: 'Hello, World!',

getMessage() {

const message = 'Hello, Earth!';

return this.message;

}

};

console.log(object.getMessage()); // 會打印什麼?

<details>
<summary>點擊查看答案</summary>

'Hello, World!' 被打印到控制枱。
object.getMessage() 是一個方法調用,所以this指向object。
方法裏面還有一個變量聲明 const message = 'Hello, Earth!'。 該變量並不會影響this.message的值。
</details>

2: Cat name

function Pet(name) {

this.name = name;

this.getName = () => this.name;

}

const cat = new Pet('Fluffy');

console.log(cat.getName()); // 會打印什麼?

const { getName } = cat;

console.log(getName()); // 會打印什麼?

<details>
<summary>點擊查看答案</summary>

控制枱會打印出'Fluffy' 和 'Fluffy'
當一個函數作為構造函數調用 new Pet('Fluffy') 時,構造函數內部的 this 等於構造的對象。
Pet構造函數中的 this.name = name 代碼會在構造的對象上創建 name 屬性。
this.getName = () => this.name 在構造的對象上創建一個方法 getName 。 並且由於使用了箭頭函數,所以箭頭函數內部的 this 就等於外部作用域的 this——構造函數 Pet。
調用 cat.getName() 和 getName(),返回的結果都是為“Fluffy”。
</details>

3.setTimeout和this

const object = {
  message: 'Hello, World!',
  logMessage() {
    console.log(this.message); // 會打印什麼?
  }
};
setTimeout(object.logMessage, 1000);

<details>
<summary>點擊查看答案</summary>

延遲 1 秒後, undefined 會打印到控制枱。
雖然 setTimeout() 函數使用 object.logMessage 作為回調,但它會將 object.logMessage 作為常規函數而不是方法。

並且在常規函數調用期間,this指向全局對象,在瀏覽器環境的情況下是window。

這就是 logMessage 方法中的 console.log(this.message) 打印undefined的 的原因。

</details>

附帶挑戰:如何修復此代碼以便'Hello,World!' 打印到控制枱?

4.人工方法

如何調用 logMessage 函數才能使他打印出“Hello, World!”?

const object = {

message: 'Hello, World!'

};

function logMessage() {

console.log(this.message); // "Hello, World!"

}

// 這裏寫下你的代碼...

<details>
<summary>點擊查看答案</summary>

至少有 3 種方法可以對象的方法調用 logMessage() 。

const object = {

message: 'Hello, World!'

};

function logMessage() {

console.log(this.message); // logs 'Hello, World!'

}

// 使用 func.call() 

logMessage.call(object);

// 使用 func.apply() 

logMessage.apply(object);

// Creating a bound function

const boundLogMessage = logMessage.bind(object);

boundLogMessage();

</details>

5.箭頭函數

const object = {

who: 'World',

greet() {

return `Hello, ${this.who}!`;

},

farewell: () => {

return `Goodbye, ${this.who}!`;

}

};

console.log(object.greet()); // 會打印什麼?

console.log(object.farewell()); // 會打印什麼?

<details>
<summary>點擊查看答案</summary>

'Hello, World!' 和 'Goodbye, undefined!' 會被打印到控制枱。
當調用 object.greet() 時,在方法greet() 中,因為greet 是一個常規函數,this指向object。 因此 object.greet() 返回 'Hello, World!'。

但是farewell() 是一個箭頭函數,所以箭頭函數內部的this總是等同於外部作用域的this。

farewell() 的外部作用域是全局作用域,這裏 this 是全局對象。 因此 object.farewell() 實際上返回“Goodbye, ${window.who}!”,其計算結果為“Goodbye, undefined!”。

</details>

 6.困惑的length

以下代碼會打印什麼?

var length = 4;

function callback() {

console.log(this.length); // What is logged?

}

const object = {

length: 5,

method(callback) {

callback();

}

};

object.method(callback, 1, 2);

<details>
<summary>點擊查看答案</summary>

4會被打印到控制枱中。
callback() 是以常規函數方式來調用的。 由於在常規函數調用時this指向全局對象,因此在callback()函數內的this.length 被評估為 window.length。

在最外層的作用域中,第一條語句 var length = 4,在全局對象上創建了一個屬性 length:window.length 變為 4。

最後,在 callback() 函數中 this.length 計算為 window.length ,所以4 被記錄到控制枱。
</details>

7.調用參數

var length = 4;

function callback() {

console.log(this.length); // What is logged?

}

const object = {

length: 5,

method() {

arguments[0]();

}

};

object.method(callback, 1, 2);

<details>
<summary>點擊查看答案</summary>

3 會被打印到控制枱。
obj.method(callback, 1, 2) 使用 3 個參數調用:callback, 1 和 2。因此,method() 中的arguments變量是以下結構的類數組對象:

{
0: callback,
1: 1,
2: 2,
length: 3
}

因為arguments[0]() 是arguments對象的callback方法的調用,所以回調中的this指向arguments。 因此 callback() 中的 this.length 與 arguments.length 相同,即 3。
</details>

總結

如果您正確回答了 5 個或更多問題,那麼您就對this關鍵字有了很好的理解!

否則,您需要好好複習一下this關鍵字。

作者:Dmitri Pavlutin 譯者:前端css和js乾貨 來源:dmitripavlutin

Add a new 评论

Some HTML is okay.