this
是 JavaScript 的一個關鍵字this
是 function 執行時,自動生成的一個內部物件this
所指向的值,也會有所不同this
與 function 在何處被宣告完全無關,而是取決於 function 被呼叫的方式this
代表的就是呼叫 function 的物件 (owner Object of the function)
this
指的就是上層物件當 function 被呼叫的當下如果沒有值或在 func.call(null)
、func.call(undefined)
這類的情況下,此時 function 裡的 this
會自動綁定至全域物件:
在嚴格模式下是 undefined
;非嚴格模式底下就是全域物件:
window
global
即使在 global scope 宣告了 function,只要它成為某個 object 的參考屬性 (reference property),在那個 function 被呼叫的當下,該 function 即被那個物件所包含。Function 可以作為某個 object 的 method 調用,這時 this
指的就是這個上層物件。
this
就是那個物件 (owner object)// 在 global 宣告了 `test` 函式
function test() {
console.log(this.x);
}
var obj = {};
obj.x = 1;
obj.m = test; // `test` 函式被傳址為 obj 物件的屬性(賦值但沒有被呼叫)
// 在 global 透過 `obj` 物件呼叫 `m` method
obj.m(); // 1
test(); // undefined
上面這個例子中,
obj.m()
輸出 1
:test
被作為物件 obj.m
的參考屬性 (reference property, function is passed by reference),雖然是在最外層呼叫了 obj.m()
,但這邊的 this
指向的是 function 的上層,也就是 obj
。test()
輸出 undefined
:當 test()
在 global scope 被調用, this
指向的是 window
,而 windon
並沒有 x
這個變數所以是 undefined
再看看另一個例子:
var obj = {
a:10,
b:{
fn:function(){
console.log(this.a); //undefined
}
}
}
obj.b.fn();
上述程式碼中, this
的上一層是 b
物件,但 b
內部沒有 a
,所以是 undefined
。
this
則是全域物件var obj = {
a:10,
b:{
x:12,
fn:function(){
console.log(this.x); //undefined
console.log(this); //window
}
}
}
var j = obj.b.fn;
j();
這邊可能會誤以為 fn
的上一層是 b
,這樣 x
應該是 12
、this
應該是 b
才對呀,怎麼會是 undefined
跟 window
呢?
雖然 fn
是 b
的 method,但是 fn
賦值給 j
的時候並沒有執行,所以此時 this
的對象仍是全域變數所在的 window
。
當我們宣告全域變數 var j = obj.b.fn
時,實際上 j
是 window.j
,而執行 j()
的時候等同於執行 window.j()
。於是此時的 this
是 window
,而 this.x
是 undefined
。
決定 this
的關鍵不在於它屬於哪個物件,而是在於 function「呼叫的時機點」。
this
就是那個物件 (owner object)this
指向的則是全域物件。透過 apply()
/ call()
/ bind()
的 function methods,改變 function 的 this
。
這些 methods 的第一個參數就是改變後調用這個 function 的對象,這時 this
指的就是第一個參數。
var x = 0;
function test() {
console.log(this.x);
}
var obj = {};
obj.x = 1;
obj.m = test;
obj.m() // 1
obj.m.apply(obj) // 1
call
跟 apply
'use strict'; // 嚴格模式
function hello(a, b){
console.log(this, a, b)
}
// 直接呼叫 function
hello(1, 2) // undefined 1 2
// call
hello.call(this 的值, 1, 2) // this的值 1 2
// apply - 要傳進去的參數是 array
hello.apply(this 的值, [1, 2]) // **undefined** 1 2
.call()
傳入參數的方式是由「逗點」隔開.apply()
則是傳入整個陣列作為參數this
的值:第一個參數傳什麼,裡面 this 的值就會是什麼。儘管原本已經有 this,也依然會被這種方法給覆蓋掉Bind
'use strict';
function hello() {
console.log(this)
}
const myHello = hello.bind('my')
myHello() // my
bind
會回傳一個新的 function,在這邊我們把 hello 這個 function 用 my
來綁定,所以最後呼叫 myHello() 時會輸出 my
。
一但 bind
了以後值就不會改變:
'use strict';
function hello() {
console.log(this)
}
const myHello = hello.bind('my')
myHello.call('call') // my,即使用 call 將 this 修改為 'call' 仍不會改變
bind()
讓 function 在被呼叫前先綁定某個物件,使它不管怎麼被呼叫都能有固定的 this
。bind()
尤其常用在像是 callback function 這種類型的場景,可以想像成是先綁定 this
,然後讓 function 在需要時才被呼叫.call()
與 .apply()
則是使用在 context 較常變動的場景,依照呼叫時的需要帶入不同的物件作為該 function 的 this
。在呼叫的當下就立即執行。在「非嚴格模式」底下,無論是用 call、apply 還是 bind,你傳進去的如果是 primitive 都會被轉成 object,舉例來說:
function hello() {
console.log(this)
}
hello.call(123) // [Number: 123]
const myHello = hello.bind('my')
myHello() // [String: 'my']
當「隱含式綁定」與「顯式綁定」衝突時,此時 this 會以「顯式綁定」為主
我覺得這篇「What's THIS in JavaScript ? [下]」總結得很好,可以直接透過這樣的順序來辨別出 this
到底是誰。
綜合上述介紹,我們可以簡單總結出一個結論:
new
進行的嗎? 如果是,那 this
就是被建構出來的物件。.call()
或 .apply()
的方式呼叫的嗎? 或是 function 透過 .bind()
指定? 如果是,那 this
就是被指定的物件。this
就是那個物件。this
就一定是全域物件: window
或是 global
,在嚴格模式下則是 undefined
。而決定
this
是誰的關鍵:
.bind()
來指定 this 是誰。call()
或 apply()
來呼叫時, this
會指向第一個參數,且會立即被執行。this
會指向呼叫 callback function 的物件。.bind()
特性,此時 this
無法複寫。or
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up
Syntax | Example | Reference | |
---|---|---|---|
# Header | Header | 基本排版 | |
- Unordered List |
|
||
1. Ordered List |
|
||
- [ ] Todo List |
|
||
> Blockquote | Blockquote |
||
**Bold font** | Bold font | ||
*Italics font* | Italics font | ||
~~Strikethrough~~ | |||
19^th^ | 19th | ||
H~2~O | H2O | ||
++Inserted text++ | Inserted text | ||
==Marked text== | Marked text | ||
[link text](https:// "title") | Link | ||
 | Image | ||
`Code` | Code |
在筆記中貼入程式碼 | |
```javascript var i = 0; ``` |
|
||
:smile: | ![]() |
Emoji list | |
{%youtube youtube_id %} | Externals | ||
$L^aT_eX$ | LaTeX | ||
:::info This is a alert area. ::: |
This is a alert area. |
On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?
Please give us some advice and help us improve HackMD.
Syncing