JavaScript - this
此筆記非原創,大部分內容參考 Huli 文章 淺談 JavaScript 頭號難題 this:絕對不完整,但保證好懂 撰寫。
Call()
& Apply()
運用
Function 調用方式
fn(arguments)
( 一般調用,屬於語法糖 )fn.call(this指向, arguments)
( 隱式調用 )fn.apply(this指向, [arguments])
( 隱式調用 )
function test() {
console.log('test')
}
test() === test.call() // true
test() === test.apply() // true
call
和 apply
的區別僅僅是第二個參數的差異
call
可以從第 2 個參數傳到 n 個參數fn.call(undefined, 1, 2, 3, 4...)
。apply
在第 2 個參數傳入陣列,後面再傳入則無效fn.apply(undefined, [1, 2, 3, 4...])
。
call()
可以傳入多個參數 :
function test(a, b, c) {
console.log(arguments)
}
test.call(undefined, 1, 2, 3)
// Arguments(3) [1, 2, 3]
apply()
則是傳入一個陣列參數 :
function test(a, b, c) {
console.log(arguments)
}
test.apply(undefined, [1, 2, 3])
// Arguments(3) [1, 2, 3]
call()
傳入陣列 :
function test(a, b, c) {
console.log(arguments)
}
test.call(undefined, [1, 2, 3])
// Arguments [[1, 2, 3]]
apply()
傳入多個陣列參數沒用 :
function test(a, b, c) {
console.log(arguments)
}
test.apply(undefined, [1, 2, 3], [4, 5, 6], [7, 8, 9])
// Arguments(3) [1, 2, 3]
call
和 apply
是為了改變 this
指向而存在的
const obj1 = {
num: 20,
fn(n) {
console.log(this.num + n)
},
}
const obj2 = {
num: 15,
fn(n) {
console.log(this.num - n)
},
}
obj1.fn(10) // ?
obj1.fn.call(obj2, 10) // ?
obj1.fn(10)
的執行結果 ?
30
,由 obj1 呼叫 fn(10)
,因此 this
指向 obj1
。
obj1.fn.call(obj2, 10)
的執行結果 ?
25
,因為 this
已經指向 obj2
,所以 obj1
的 fn(n)
裡面所取得的 this.num
會是 obj2
的 num: 15
。
如何得知 this 指向誰 ?
💡 一旦脫離了物件,不太需要關注 this
的值,因為沒什麼意義。
// 無意義的 this
function hello() {
console.log(this)
}
hello() // ?
- 嚴格模式回傳
undefined
- 非嚴格模式回傳
window
- 非嚴格模式,node.js 回傳
global
this
的值與作用域、程式碼的位置在哪裡完全無關,只跟「你如何呼叫」有關。
範例 :
const obj = {
num: 1,
hello() {
console.log(this)
},
}
obj.hello() // {num: 1, hello: ƒ}
const hey = obj.hello
hey() // window
誰呼叫函式,就把誰放進 call 第一個參數 :
obj.hello.call(obj) // this 指向 obj,印出 {num: 1, hello: ƒ}
hey.call() // this 指向 window,印出 Window{...}
變異題 :
const num = 10
const obj = {
num: 20,
fn() {
function test() {
console.log(this.num)
}
test()
},
}
obj.fn() // ?
obj.fn()
的執行結果為何 ?
答案是 undefined
真正呼叫 this
的是 test
這個函式,改成使用 call 呼叫 : test.call()
,在沒有指定 call 第一個參數時,都是預設綁定全域,也就是 window
。
若今天外層的 num
是使用var
宣告,則答案會是 10
,但 let
和 const
都有自己的區塊作用域,因此在 this
指向全域下讀取不到 num
,所以為undefined
。
this 面試題
1. this 是什麼 ? 什麼是 this ? this 是什麼是 this ? 什麼是 this 是什麼 ? ( 夠了...
每一個 function 在被執行的時候都會有一個 reference ( 參照 ) 指向 所屬的環境 ,這就是 this。
2. Function 有哪些調用的方式 ? Function 裡面的 this 又是指向誰 ?
一般調用
fn()
,function ( fn()
) 的 this
指向全域物件,非嚴格模式下為 window
,嚴格模式下為 undefined
。
物件中調用
obj.fn()
,function ( obj.fn()
) 裡面的 this 指向呼叫他的物件 ( obj
)。
建構式中調用
const john = new Person()
,建構式 ( Person
) 的 this
指向被建構的物件 ( john
)。
隱式調用
fn.call()
fn.apply()
fn.bind()
,使用 call、apply、bind 方式將第一個參數指定 this 指向任何物件。
3. 以下這個 this 代表什麼呢 ?
function a() {
console.log(this)
}
Answer
this
的值與作用域和程式碼位置完全無關,只跟「你如何呼叫」有關。