目錄
- 序言
- Function.prototype.bind() 方法
- 箭頭函式
- 參考
1.序言
在 深入理解JS:執行上下文中的this(一) 中,我們主要深入分析全域性環境和函式環境中函式呼叫的 this,還留下 bind 方法以及箭頭函式的 this 尚未分析,因此我們將在這篇文章進行講解。
2.Function.prototype.bind() 方法
bind() 方法將會建立返回一個新的函式。在 bind() 被呼叫時,這個新函式的 this 將被指定為 bind() 的第一個引數,而其餘引數將作為新函式的引數,供呼叫時使用。
ES5 引入了 bind 方法來設定函式的 this 值,而不用考慮函式如何被呼叫的。
這裡給出一種 bind() 的實現演算法:
var slice = Array.prototype.slice;
Function.prototype.bind = function() {
var thatFunc = this, thatArg = arguments[0];
var args = slice.call(arguments, 1);
if (typeof thatFunc !== 'function') {
throw new TypeError('Function.prototype.bind called on incompatible ' + thatFunc);
}
return function(){
var funcArgs = args.concat(slice.call(arguments))
return thatFunc.apply(thatArg, funcArgs);
};
};
注:上述程式碼並沒有完全按照ES5規範實現,只是作為一種實現參考,更加完善的解決方案可以參考 function-bind
但不論哪種實現,其實質上都是通過類似 Function.prototype.apply(thisArg, argArray)
來是實現指定呼叫函式 this 的。
3.箭頭函式
箭頭函式表示式的語法比函式表示式更簡潔,並且沒有自己的 this,arguments,super 或 new.target。它很適合用作匿名函式,並且不能用作建構函式(為什麼呢?詳情點選檢視)。
ES6 引入了支援 this 詞法解析的箭頭函式(它在閉合的執行環境內設定 this 的值)。
如何理解箭頭函式在閉合的執行環境內設定 this 的值?
簡單理解,箭頭函式不會建立自己的 this,它的 this 與封閉詞法環境的 this 保持一致,即如果箭頭函式在全域性環境中,那麼它的 this 就指向全域性物件,如果箭頭函式在某一個函式中,那麼它的 this 就指向所在函式的 this。
我們來看幾個示例:
(1)全域性環境
var global = this
var foo = () => { return this }
var value = 1
var bar = {
value: 2,
getValueByArrowFunc: () => {
return this.value
},
getValue: function (){
return this.value
},
}
console.log(foo() === global) // true
// 箭頭函式 this => global
console.log(bar.getValueByArrowFunc()) // 1
// 普通函式 this => bar
console.log(bar.getValue()) // 2
(2)函式環境
ES6的語法:
function foo() {
this.value = 1
// 箭頭函式表示式
var arr = () => {
console.log(this.value)
}
arr()
}
轉化為ES5:
function foo() {
var _this = this;
this.value = 1;
// 轉化為普通函式表示式
var arr = function arr() {
console.log(_this.value);
};
arr();
}
對比轉化前後的程式碼可以看出:箭頭函式會轉化為一個普通函式,通過一個臨時變數 _this 來傳遞,它之前的 this 就是所在函式的 this
(3)call() 、 apply() 或 bind() 方法
var global = this
var foo = {
bar: () => {
return this
}
}
var obj = { value : 1 }
console.log(foo.bar() === global) // true
console.log(foo.bar.call(obj) === global) // true
console.log(foo.bar.apply(obj) === global) // true
var bind = foo.bar.bind(obj)
console.log(bind() === global) // true
由於箭頭函式不會建立自己的 this,那麼通過 call() 、 apply() 或 bind() 方法呼叫一個箭頭函式時,只能傳遞引數,第一個引數會被忽略。
4.參考
this 關鍵字 - JavaScript | MDN - Mozilla