本篇為 [JS201] 進階 JavaScript:那些你一直搞不懂的地方筆記之六。
重點整理:
1. 為什麼要用 this? 在物件導向裡面,this 用來對應到 instance
2. this 的值說清楚
a. 物件導向:this 代表 instance
b. 非物件導向:
b.1: 嚴格模式下為 undefined
b.2: 非嚴格模式下,browser 為 window;node.js 為 global
b.3: 例外: DOM 裡面,點擊到誰,this 就是誰
c. 物件:跟函式怎麼被呼叫有關;可以用 .call()
小撇步判斷
d. 例外: 箭頭函式裡面,跟在哪裡被定義有關,很像 scope 的概念
3. 強制綁定 this
先學完物件導向,學 this 才有意義
一、this 的意義在哪
在物件導向裡面,可以用 this 代替、對應到 instance,不然也沒有其他方法可以用了。
this 之所以不好理解,是因為「在非物件導向」的情況下,不太容易準確的判斷它的值。
接下來我們來看在「在非物件導向」的情況下,this 的值是什麼。
二、在沒有意義的地方(非物件導向)呼叫 this,預設值會是什麼?
1. 非物件導向,this 分別的值
在非物件導向環境下,this 跟函式沒有什麼關聯性(但 DOM 是一個例外)
a. 在寬鬆模式下的預設值:
function test() {
console.log(this)
}
test() // global or window
a.1 在瀏覽器,this 為 window
a.2 在 node.js,this 為 global
b. 在嚴格模式下,this 的值會是 undefined
'use strict'
function test() {
console.log(this)
}
test() // undefined
2. 例外情形:用 DOM 的時候
document.querySelector('.btn').addEventListener('click', function() {
this // 點到哪個按鈕,this 就是哪個按鈕
})
三、另外兩種呼叫 function 的方法:call 與 apply
a. .call()
'use strict'
function test() {
console.log(this)
}
test.call('123') // 裡面傳什麼,this 就是什麼
b. .apply()
'use strict'
function test() {
console.log(this)
}
test.apply(123) // 裡面傳什麼,this 就是什麼
c. 兩者差別
'use strict'
function test(a, b, c) {
console.log(this)
console.log(a, b, c)
}
test.call(123, 1, 2, 3) // 第一個參數為 this,接著傳 a, b, c 三個參數
test.apply(123, [1, 2, 3]) // 第一個參數為 this,第二個參數為陣列
四、用另一種角度來看 this 的值
1. 來看在「物件」的情況下,this 的值會是什麼呢?這裡說的是物件喔,跟物件導向不一樣,要特別注意。
this 的值跟在哪裡被宣告或定義沒有關係,取決於「怎麼呼叫」
const obj = {
a: 123,
test: function() {
console.log(this) // 就是 obj 本身
}
}
obj.test() // { a: 123, test: [Function: test] }
什麼叫做「取決於在哪裡被呼叫呢」,例如說,下面這個方式,this 就會是 undefined
'use strict'
const obj = {
a: 123,
test: function() {
console.log(this)
}
}
var func = obj.test
func() // undefined
2. 判斷 this 小撇步: 在呼叫的函式上加上 .call()
例如一開始的例子,可以看作這樣 obj.test() => obj.test.call(obj)
const obj = {
a: 123,
test: function() {
console.log(this)
}
}
obj.test()
或者是看另一個範例,可以看作 obj.inner.test() => obj.inner.test.call(obj.inner)
'use strict'
const obj = {
a: 123,
inner: {
test: function() {
console.log(this)
}
}
}
obj.inner.test()
再看一個例子,可以看作 func.call()
,出來就是 undefined
'use strict'
const obj = {
a: 123,
inner: {
test: function() {
console.log(this)
}
}
}
const func = obj.inner.test
func() // undefined
五、強制綁定 this:bind
利用 .bind()
強制改變 this 的值
綁定完以後,不管呼叫方式為何,this 的值都不會變
.bind()
以後,會回傳一個函式
'use strict'
const obj = {
a: 123,
test: function() {
console.log(this)
}
}
const bindTest = obj.test.bind(obj)
bindTest() // { a: 123, test: [Function: test] }
綁完以後,不管用任何方法,都不會影響 this 的值
'use strict'
const obj = {
a: 123,
test: function() {
console.log(this)
}
}
const bindTest = obj.test.bind(obj)
bindTest.apply('111') // 仍然是 obj
bindTest.call('111') // 仍然是 obj
六、arrow function 的 this
箭頭函式限定:箭頭函式裡面的 this,跟你怎麼呼叫沒有關係,跟 scope 比較像,跟你定義在哪裡有關係。
因此下面兩個都會是 Test {}
class Test {
run () {
console.log('run this:', this)
setTimeout(() => {
console.log(this)
}, 100);
}
}
const t = new Test()
t.run()
假設不用箭頭函式呢?
class Test {
run () {
console.log('run this:', this) // Test {}
setTimeout( function() {
console.log(this) // undefined
}, 100);
}
}
const t = new Test()
t.run()
以下為閱讀 淺談 JavaScript 頭號難題 this:絕對不完整,但保證好懂 筆記
一但脫離了物件導向,其實 this 就沒有什麼太大的意義
怎麼更改 this 的值?
可以用 call、apply 與 bind 改變 this 的值
待讀文章: