JavaScript #9 — This (上)

Thomas Hung
Thomas 學習筆記
8 min readMay 17, 2020

This

This 是什麼?This 指向誰?This 的型別又是什麼?先來簡單說明一下 :

  • This 是在 JavaScript 中的關鍵字。
  • This 是在 函式(Function)執行時所產生的內部物件。
  • This 是依 函式 (Function) 執行時機環境不同,其指向的物件也有所不同。
  • This 在嚴格模式下會回傳 undefined
  • This 在 DOM element 的監聽事件中指向觸發節點元素。

以上說明了這麼多,This 在不同的時機環境下,產生結果也有所不同。

預設綁定 (Default Binding)

在全域環境下的變數或函式沒有特別綁定 this 的狀況下,會指向預設綁定中的 window ,也就是全域物件(屬性)。

this === window  //true

再來看看 函式的範例 :

function foo(){ 
console.log(this)
}
foo() //window

沒有錯, foo() 函式在全域環境下執行時,this 會預設指向 window 。

var a = 'outer';function foo() {
console.log(this.a);
function boo() {
console.log(this.a);
function bar() {
console.log(this.a);
}
bar(); //'outer'
}
boo(); //'outer'
}
foo(); //'outer'

不管在任何一層呼叫函式都是指向 全域 window.a 物件。

但是在嚴格模式下,this 的值就會改為 undefined,而不是 window。

顯式綁定 (Explicit Binding)

那如果要明確的指定 this 指向某個物件呢?

在 函式 (Function)中有三個方法可以明確的指定 this 要綁定哪個物件,分別是 :call()apply()bind()

bind( )

在以下的範例中,執行 obj.funcA() 函式可以發現到 funcA() 中的 this.word 指向 obj 物件中的 word,但 funcB() 中的this.word 是指向全域物件中的 age (以 var宣告變數為 全域的屬性 參考 : JavaScript #1 — 運算子、運算式、值與型別、變數 ),因執行 funcB() 函式時,並沒有明確指定 this 要綁定哪個物件,會依照上述的 預設綁定給 全域物件 (window),那就是 window.word回傳值為 35。

var word = 'DEF'var obj = {
word: "ABC",

funcA: function () {
console.log(this.word) //ABC
function funcB() {
console.log(this.word) //DEF
}
funcB()
}
}
obj.funcA()

那如果要強制綁定 this 呢!可以使用 bind() 方式綁定。

var word= 'DEF'var obj = {
word: "ABC",

funcA: function () {
console.log(this.word) //ABC
function funcB() {
console.log(this.word) //ABC this.word 指向 obj 中的 word
}
funcB.bind(obj)() //使用 bind() 方式綁定
}
}
obj.funcA()

在執行 funcB() 函式時先使用 bind() 綁定 this 的物件為 obj ,之後再 funcB() 函式中的 this.word就會暫時強制指向 obj 物件中的 word,傳回結果為 ABC

call( ) & apply( )

再來說明這二種方法,那使用以下範例來說明 :

let obj = {
word: 'ABC',
foo: boo,
};
function boo() {
console.log(this.word);
}
obj.foo(); //ABCboo(); //undefined

在執行 obj 物件中的 foo 函式 為 隱含式綁定(這部份之後會再提到),所以 foo 函式中的 this.word 會指向 obj 物件中的 word ,回傳結果 ABC

但執行 boo() 函式時,確回傳值為 undefined ,就如同之前的 預設綁定方式,在全域環境下執行 boo() 函式時, 函式中的this.word 會指向全域物件的 window.word 變數,可是在全域物件並沒有word 變數,則會回傳值為 undefined參考 : JavaScript #1 — 運算子、運算式、值與型別、變數

這時就可以使用 call()apply() 來強制綁定 this 的物件如以下範例 :

function Foo(name) {
console.log(` Name: ${name} / Age : ${this.age}`)
}
let obj = {
age: 33
}
//Name: ABC / Age : 33
Foo.call(obj, 'ABC')
//Name: CDE / Age : 33
Foo.apply(obj, ['CDE'])

如上述範例中,在呼叫 Foo() 函式前先以 call()apply() 來強制綁定 this 的物件為 obj ,回傳的結果就如上述的一樣。

這時會發現,這兩種的方式不同之處,call()apply() 中第一個引數為 thisArg ,強制指定某個物件作為該 function 執行時的 this ,之後只差別要輸入函式的參數有所不同而以,call() 以 逗號隔開每個傳入的參數,而 apply()則是傳入 陣列為參數。

call() 、apply()、bind() 差異

  • bind() : 在呼叫函式前先綁定 thisArg的物件,並在執行時都能有固定的 this 物件 (特性 用來建立新的函式)。
  • call() 、apply() :會依照執行當下的不同並帶入不同所需 thisArg的物件 (特性 當下執行函式),且 thisArg較常變動的當下。
參考 : JavaScript Function (函式)-學習筆記

隱含式綁定 (Implicit Binding)

在全域環境下,如呼叫函式 (Function) 為物件中的方法,執行函式時 this 就會綁定該物件。

let obj = { number: 37 };function getNum() {
return this.number
};
obj.func = getNum;console.log(getNum()); //undefinedconsole.log(obj.func()); // 37

從此範例來看,當 getNum() 在全域環境下呼叫時,函式中的this.number 會指向全域物件的 window.number 變數,但在全域物件中並沒有number 變數,則會回傳值為 undefined,此為 預設綁定。

當我們在 obj 物件中取得 func 屬性時,會呼叫全域環境下的 getNum() 函式,當中 this.numberthis 會指向 obj 物件(上層的物件為 obj ),於是此時 obj.func() 的值為 37。

以上為 隱含式綁定 (Implicit Binding) 。

再來看看另個範例 :

let obj2 = { number: 7, obj2Num: getNum }let obj1 = { number: 37, obj1Num: obj2 }function getNum() {
return this.number
}
obj1.obj1Num.obj2Num() //7 指向 obj2 物件中的 number

obj1 物件取得 obj1Num 屬性時,此屬性會去取得 obj2 中在全域環境下的 getNum() 函式,並將 this.number 指向 obj2 中的物件,所以回傳值為 7,由此可見 決定 this 的時機點(是在被呼叫的時候決定)是上一層的物件才是有用的。(正好相反於 範圍鏈 (Scope Chain) 當中變數是 被定義的當下決定 )參考 : JavaScript #5 — 閉包(Closure)、範圍鏈(Scope Chain)

參考:鐵人賽:JavaScript 的 this 到底是誰?thisJavaScript thisThe JavaScript this Keyword

以上是我對 JavaScript #9 — This (上) 的學習筆記 😉。

***如果有任何想法,也歡迎留言與我分享~***

--

--

Thomas Hung
Thomas 學習筆記

when you feel like quitting,think about why you started.