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 的值與作用域和程式碼位置完全無關,只跟「你如何呼叫」有關。