對於寫 JS 的朋友,我想這主題算是 最熟悉的陌生人
,對於新手來說這是必懂的主題,對於資深的人來說可能在這上面踩過不少雷,但你真的懂嗎 ? 到底什麼是 this ?
定義上:
this 這個關鍵字代表的值為目前執行環境的 ThisBinding
在大多數情況下,this 會因為 function 呼叫的方式而有所不同
So, this
到底是什麼? 看著定義我沈默 3 秒,最好看的懂拉 ....
在開始說 this 前,我們先說說 Context(上下文):
Context 指的是函式在被
呼叫執行
時,所處的物件環境。
Context 決定了 JS 執行過程中可以獲取哪些變量、數據、函數,每一個 Context 都會綁定一個變量對象(Variable Object),它用來儲存 Context 所有已經定義的變量,函數。
Context vs Scope(作用域):
Scope 指的是在函式中變數的可使用範圍,在函式定義
的時候就已經決定了。
所以 this
表示的其實是 函數調用的上下文 (context)
,而 context 默認是全局 window。
console.log(this); // this 等於 ECMAScript 在瀏覽器環境的 global對象,window
function bar() {
'use strict'
console.log(this);
}
bar() // undefined
默認綁定作用於函數直接調用,此時 this 會指向全局 window,但嚴格模式會指向 undefined
function getName() {
console.log(this.name);
}
var meggie = {
name: 'Meggie';
}
var jacky = {
name: 'Jacky';
}
getName.apply(meggie); //'Meggie'
getName.apply(jacky); // 'Jacky'
顯示綁定的優點?
可以明確的指定要執行 function 中的 this 是什麼,不需要透過另一個變數來暫存 this 的方式來獲取,這方法也往往更直觀,不像 callback function 會改變指向。
其實 隱式綁定都只是語法糖,都可以寫成 apply,bind,call
的方式,apply,bind,call
雖然麻煩但往往更正規。
Call vs Apply vs Bind:
function.call (thisArg, arg1, arg2, ...)
function.apply (thisArg, [argsArray])
都是將 this 以及 parameters 傳入,重新定義 this
指向,而且會立刻執行前面的 function
func.bind (thisArg[, arg1[, arg2[, ...]]])
是借用舊有的函數來建立一個新的函數
,並且將 this 綁定到物件中,不會立刻執行前面的 function
Bind 函數存在著多次綁定的問題,如果多次綁定this,則以第一次為主
var obj = {
id: 10,
getId: function() {
console.log(this.id);
}
}
obj.getId() // this 為 object
隱式綁定作用於函數,首先查看是不是有Context 的對象
,如果有那麼this
會綁定到這個對象上。
隱式綁定丟失 this 的問題:
const obj = {
foo: function() {
console.log(this);
}
}
obj.foo(); // obj
setTimeout(obj.foo, 0); // window
// 解決辦法:setTimeout(obj.foo.bind(obj), 0) // obj
setTimeout(function() {
obj.foo(); // obj
},10);
為什麼作為 obj.foo()
的時候就沒問題,而 callback this卻丟失了呢? 因為 obj.foo
本身屬於匿名函數,這其實是一個函數上直接的調用,所以應用了 默認綁定
,導致 this 丟失。
const obj = {
a: function () {
console.log(this) // obj
function a1() {
console.log(this) // window
}
// 解決辦法,改用箭頭函數 var a1 = () => { console.log(this); }
a1()
}
}
obj.a()
所以來考考大家,為什麼執行 a1() 的時候返回的是 window 的 this 呢?
因為這邊的 a1() 也是屬於函數直接調用,所以為 window
function User() {}
User.prototype.getId = function() {
console.log(this.id);
}
var user = new User();
user.id = 10;
user.getId() // 10,因為 this 指向 User
new
在創建實例(instance)的時候事實上是對新實例 this 不斷地賦值,將 __proto__
指向原型。
this
值,它繼承外面作用域的 this
以下這個例子,因為 ES6 是嚴格模式,嚴格模式下的全域作用域為 undefind,所以 this 為 undefined:
const foo = (options) => {
console.log(this); // undefined
};
this 的值到底是什么?一次说清楚
JS 紀錄7 - this 指向判斷的方式
this綁定的四種方法