Skip to main content

JavaScript - this

此筆記非原創,大部分內容參考 Huli 文章 淺談 JavaScript 頭號難題 this:絕對不完整,但保證好懂 撰寫。

Call() & Apply() 運用

Function 調用方式

  1. fn(arguments) ( 一般調用,屬於語法糖 )
  2. fn.call(this指向, arguments) ( 隱式調用 )
  3. fn.apply(this指向, [arguments]) ( 隱式調用 )
function test() {
console.log('test')
}

test() === test.call() // true
test() === test.apply() // true

callapply 的區別僅僅是第二個參數的差異

  1. call 可以從第 2 個參數傳到 n 個參數 fn.call(undefined, 1, 2, 3, 4...)
  2. 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]

callapply 是為了改變 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,所以 obj1fn(n) 裡面所取得的 this.num 會是 obj2num: 15


如何得知 this 指向誰 ?

💡 一旦脫離了物件,不太需要關注 this 的值,因為沒什麼意義。

// 無意義的 this
function hello() {
console.log(this)
}

hello() // ?
  1. 嚴格模式回傳 undefined
  2. 非嚴格模式回傳 window
  3. 非嚴格模式,node.js 回傳 global
info

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,但 letconst都有自己的區塊作用域,因此在 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 的值與作用域和程式碼位置完全無關,只跟「你如何呼叫」有關。

Reference