0%

What is "this" in JavaScript

什麼是this


  • this 是 JavaScript 的一個關鍵字。
  • this 是 function 執行時,自動生成的一個內部物件。
  • 隨著 function 執行場合的不同,this 所指向的值,也會有所不同。
  • 在大多數的情況下,this 會因為 function 的呼叫方式而有所不同。

JavaScipt 的 this


JavaScript 的 this 跟其他程式語言慣用的那個 this 有了差異,這就是為什麼 this 往往不容易弄懂的原因。

儘管 this 的定義不太一樣,但我認為本質上還是很類似的。

this 的值跟作用域跟程式碼的位置在哪裡完全無關,只跟「你如何呼叫」有關

舉個例子


1
2
3
4
5
6
7
8
9
var obj = {
foo: function(){
console.log(this)
}
}

var bar = obj.foo
obj.foo() // print 出的 this 是 obj
bar() // print 出的 this 是 window

請解釋最後兩個呼叫function的值為什麼不一樣。

呼叫 Function

首先需要從呼叫function開始說起

JavaScript(ES5)裡面有有三種呼叫function的方法:

1
2
3
func(p1, p2) 
obj.child.method(p1, p2)
func.call(context, p1, p2) // 先不說 apply

一般來說常見的都是前兩種方法,而且普遍認為前兩種方法「優於」第三種方法。

從看到這文章起,你一定要記住第三種呼叫方法,才是正常呼叫用法:

1
func.call(context, p1, p2)

其他兩種都是Syntactic suga,可以等價轉換為 call

1
2
3
4
5
func(p1, p2) 等於
func.call(undefined, p1, p2)

obj.child.method(p1, p2) 等於
obj.child.method.call(obj.child, p1, p2)

(我稱為「轉換程式碼」,方便下文引用)

至此 function 呼叫只有一種方法:

1
func.call(context, p1, p2)

這樣,this 就好解釋了

this,就是上面程式碼中的 context。就這麼簡單。

this 是你 call 一個 function 時傳的 context,由於你從來不會使用 call 方法的 function 呼叫,所以你一直不知道。

先看 func(p1, p2) 中的 this 如何定義

當寫以下程式碼時

1
2
3
4
5
6
7
8
9
10
11
12
function func(){
console.log(this)
}

func()
用「轉換程式碼」把它轉換一下,得到

function func(){
console.log(this)
}

func.call(undefined) // 可以簡寫成 func.call()

按理來說 print 出来的 this 應該是 undefined 了吧,但是瀏覽器中有條規則:

如果你傳的 contextnullundefined,那麼 window 就是默認的 context

此外 use strict 下默認 contextundefined ,因此上面的 print 結果是 window

如果你希望這的 this 不是 window,很簡單:

1
func.call(obj) // 那這裡面的 this 就是 obj 了

再看 obj.child.method(p1, p2) 的 this 如何定義

1
2
3
4
5
6
7
8
9
10
11
var obj = {
foo: function(){
console.log(this)
}
}

obj.foo()
按照「轉換程式碼」,可以將 obj.foo() 轉換成

obj.foo.call(obj)
好,this 就是 obj。

回到最一開始的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var obj = {
foo: function(){
console.log(this)
}
}

var bar = obj.foo
obj.foo() // 轉換成 obj.foo.call(obj),this 就是 obj
bar()

// 轉換成 bar.call()
// 由於沒有轉換 context
// 所以 this 就是 undefined
// 最後瀏覽器给拋出默認的 this —— window

[ ] 語法

1
2
3
function fn (){ console.log(this) }
var arr = [fn, fn2]
arr[0]() // 這裡面的 this 又是什麼呢?

可以把 arr[0]( ) 想像成arr.0( ),雖然後者的語法跑起來會報錯,但是方法與轉換程式碼中的 obj.child.method(p1, p2) 對應上了,於是就可以只接把它轉換成了:

1
2
3
4
           arr[0]() 
想像為   arr.0()
然後轉換成 arr.0.call(arr)
那麼裡面的 this 就是 arr

Arrow Function

實際上 Arrow Fucntion 裡面並沒有 this,如果在 Arrow Function 看到 this,可以直接把它當成 Arrow Function 外面的 this 即可。外面的 this 是什麼,Arrow Function 裡面的 this 就是什麼,因為 Arrow Function 本身不支援 this

有人說「Arrow Function 裡面的 this 指向 Arrow Function 外面的 this」,這聽起來很傻,因為Arrow Function 内外 this 就是同一個東西,并沒有存在什麼指向不指向。

總結

this 就是你 call 一個 Function 時,傳入的第一個參數。(請務必記下來「this 就是 call 的第一個參數」)
如果你的呼叫Function方法不是 call ,請想想「轉換程式碼」將它轉乘 call 方法也許就能想情楚了。