在 JavaScript 中,this
是函數調用上下文。正是因爲 this
的行爲很複雜,因此在 JavaScript 面試中,老是會問到有關 this
的問題。javascript
作好的準備面試的方法是練習,因此本文針對 this
關鍵字整理了 7 個有趣的面試。前端
注意:下面的 JavaScript 代碼段以非嚴格模式運行。java
如下代碼輸出什麼:程序員
const object = { message: 'Hello, World!', getMessage() { const message = 'Hello, Earth!'; return this.message; } }; console.log(object.getMessage()); // => ?
輸出: 'Hello, World!'
面試
object.getMessage()
是方法調用,這就是爲何方法中的 this
等於 object
的緣由。segmentfault
方法中還有一個變量聲明 const message ='Hello,Earth!'
,該變量不會影響 this.message
的值。數組
如下代碼輸出什麼:瀏覽器
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()); // =>?
輸出:'Fluffy'
和 'Fluffy'
服務器
當一個函數被看成構造函數調用時( new Pet('Fluffy')
),構造函數內部的 this 等於構造的對象。微信
Pet
構造函數中的 this.name = name
表達式在構造的對象上建立 name
屬性。
this.getName = () => this.name
this.getName =()=> this.name 在構造的對象上建立方法 getName
。由於使用了箭頭函數,因此箭頭函數中的 this 等於外部做用域中的 this
,也就是構造函數 Pet
。
調用 cat.getName()
和 getName()
會返回表達式 this.name
,其結果爲 'Fluffy'
。
如下代碼輸出什麼:
const object = { message: 'Hello, World!', logMessage() { console.log(this.message); // => ? } }; setTimeout(object.logMessage, 1000);
延遲1秒鐘後,輸出:undefined
儘管 setTimeout()
函數使用 object.logMessage
做爲回調,但仍把 object.logMessage
做爲常規函數而非方法調用。而且在常規函數調用中 this 等於全局對象,在瀏覽器環境中是 window
。這就是 logMessage
方法內的 console.log(this.message)
輸出 window.message
的緣由,後者是 undefined
。
挑戰:怎樣修改這段代碼使其輸出 'Hello, World!'
?在下面的評論中寫出你的解決方案*
補全代碼,使結果輸出 "Hello,World!"
。
const object = { message: 'Hello, World!' }; function logMessage() { console.log(this.message); // => "Hello, World!" } // Write your code here...
至少有 3 種方式能夠把 logMessage()
做爲對象上的方法調用。任何一個都被看做是正確答案:
const object = { message: 'Hello, World!' }; function logMessage() { console.log(this.message); // => 'Hello, World!' } // 使用 func.call() 方法 logMessage.call(object); // 使用 func.apply() 方法 logMessage.apply(object); // 使用函數綁定 const boundLogMessage = logMessage.bind(object); boundLogMessage();
如下代碼輸出什麼:
const object = { who: 'World', greet() { return `Hello, ${this.who}!`; }, farewell: () => { return `Goodbye, ${this.who}!`; } }; console.log(object.greet()); // => ? console.log(object.farewell()); // => ?
輸出: 'Hello, World!'
和 'Goodbye, undefined!'
當調用 object.greet()
時,在方法 greet()
內部 this
的值等於 object
,由於 greet
是常規函數。因此 object.greet()
返回 'Hello,World!'
。
可是 farewell()
是一個箭頭函數,因此箭頭函數中 this 的值老是等於外部做用域的 this
。farewell()
的外部做用域是全局做用域,其中 this
是全局對象。因此 object.farewell()
實際上會返回 'Goodbye, ${window.who}!'
,其結果爲 'Goodbye, undefined!'
。
如下代碼輸出什麼:
var length = 4; function callback() { console.log(this.length); // => ? } const object = { length: 5, method(callback) { callback(); } }; object.method(callback, 1, 2);
輸出:4
使用 method()
內部的常規函數調用來調用 callback()
。由於在常規函數調用期間的 this 值等於全局對象,因此在 callback()
函數中 this.length
爲 window.length
。
位於最外層的第一個語句 var length = 4
在全局對象上建立了屬性 length
,因此 window.length
變爲 4
。
最後,在 callback()
函數內部,`this.length
的值爲 window.length
,最後輸出 4
。
如下代碼輸出什麼:
var length = 4; function callback() { console.log(this.length); // 輸出什麼 } const object = { length: 5, method() { arguments[0](); } }; object.method(callback, 1, 2);
輸出:3
obj.method(callback, 1, 2)
用了 3 個參數進行調用:callback
、1
和 2
。結果 method()
內的arguments
特殊變量是有如下結構的相似數組的對象:
{ 0: callback, 1: 1, 2: 2, length: 3 }
由於 arguments[0]()
是對 arguments
對象上 callback
的方法調用,因此 callback
內部的 this
等於 arguments
。結果在 callback()
內部的 this.length
與 arguments.length
是相同的,都是3
。
若是你答對了 5 個以上,那麼你對 this
關鍵字掌握的狀況是很不錯的。