this
剛剛提的那些物件導向的例子,我們使用到了很多次 this
,this 就是一個提供給物件導向來使用的,因為有了 this ,這樣 JS 才知道我們是指哪一個實例。
但是在物件導向以外也是可以使用 this,只是值可能會和在物件導向不一樣,例如在瀏覽器下 this 預設值就是 window,node.js 下就是 global,而且如果你是以嚴格模式 ( 'use strict' ) 下的話,this 就會變成 undefined。
'use strict'
function test(){
console.log(this) // undefined
}
test()
call 與 apply
不過,如果在呼叫 function 時是使用 call
或 apply
的話,this的值就會不一樣了,此時的 this 就會取決 call
或 apply
的第一個參數是什麼。
'use strict'
function test(){
console.log(this) // OMG
}
test.call('OMG')
學了 call ,之後我們就可以利用 call 來更了解 this:
'use strict'
const obj = {
a: 666,
inner: {
test: function() {
console.log(this)
}
}
}
obj.inner.test() //{test: ƒ}
此時當你在執行 obj.inner.test()
,可以想像成像這樣 obj.inner.test.call(obj.inner)
。
如果我們新增一個變數放 obj.inner.test ,然後去呼叫呢?
'use strict'
const obj = {
a: 666,
inner: {
test: function() {
console.log(this)
}
}
}
const fn = obj.inner.test
fn()
在嚴格模式下,去呼叫 fn 的話,我們會得到 undefined,在寬鬆模式下,我們會得到 winodw。如果你用 call 去理解的話,就不會覺得那麼弔詭了,
當我們執行 fn()
就等於 fn.call(undefined) ,因為 this 取決於我們怎麼呼叫 function,如果是使用 call 或 apply 就是看第一個參數放什麼。
bind
bind 的行為跟 call 與 apply 很像,只是 call 與 apply,會直接呼叫 function,而 bind 是回傳一個 function。
'use strict'
const obj = {
a: 666,
inner: {
test: function() {
console.log(this)
}
}
}
const fn = obj.inner.test.bind('OMG')
fn()
this 會取決於 bind 的參數是什麼,所以此時就算使用 call 呼叫 fn fn.call('666')
,也是一樣會回傳 OMG。
arrow function 中的 this
arrow function 裡面的 this,跟剛剛說的 this 規則,是不一樣的,arrow function 裡面的 this,會取決於作用域。
'use strict'
const calcAge = function (birthYear) {
console.log(2021- birthYear) //32
console.log(this) // undefined
}
calcAge(1989)
如果改成 arrow function 的話
'use strict'
const calcAge = (birthYear) => {
console.log(2021 - birthYear) //32
console.log(this) //window
}
calcAge(1989)
為什麼會回傳 window 呢,這是因為在 arrow function 裡面的 this,其實就是上一層的 EC 裡面的 this,而上一層的 this,就是 window。
對於 this 和 JS 中的物件導向 有了一定的基礎概念後,現在我們可以來到最終章,再一次複習在 JS 中要怎麼實現物件導向的類別與實例 。