徹底了解 this

ECMAScript 的一大特色是 Function 能透過 call()apply()bind() 去動態改變 this,尤其在寫 Vue 時特別重要,因為 Vue 預設會將 this 指向 Vue Instance,若你自行抽 function 時,觀念不清楚很容易使 this 就指向 undefined,所以寫 Vue 一定要搞清楚 ECMAScript 的 this

Version


ECMAScript 5
ECMAScript 2015

Scope


Sloppy Mode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const outerThis = this;

function func1() {
console.log(this === outerThis);
}

const func2 = function() {
console.log(this === outerThis);
};

const func3 = () => {
console.log(this === outerThis);
};

func1();
func2();
func3();

在 Sloppy Mode 分別以 Function Declaration、Anonymous Function 與 Arrow Function 三種方式檢視 this

this002

outerThiswindow

  1. 在 Sloppy Mode 下,Function Declaration 的 thiswindow,因此為 true
  2. 在 Sloppy Mode 下,Anonymous Function 的 thiswindow,因此為 true
  3. 在 Sloppy Mode 下,Arrow Function 的 this 為 parent scope 的 window,因此為 true

Strict Mode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
"use strict";

const outerThis = this;

function func1() {
console.log(this === outerThis);
}

const func2 = function() {
console.log(this === outerThis);
};

const func3 = () => {
console.log(this === outerThis);
};

func1();
func2();
func3();

在 Strict Mode 分別以 Function Declaration、Anonymous Function 與 Arrow Function 三種方式檢視 this

this003

outerThiswindow

  1. 在 Strict Mode 下,Function Declaration 的 thisundefined,因此為 false
  2. 在 Strict Mode 下,Anonymous Function 的 thisundefined,因此為 false
  3. 在 Strict Mode 下,Arrow Function 的 this 為 parent scope 的 window,因此為 true

Function Declaration 與 Anonymous Function 在 Sloppy Mode 與 Strict Mode 下的 this 意義不一樣,分別是 windowundefined;但 Arrow Function 在 Sloppy Mode 與 Strict Mode 下的 this 始終都是 parent scope 的 window

Function Declaration


Sloppy Mode

1
2
3
4
5
6
7
8
9
10
const outerThis = this;

function func() {
console.log(this === outerThis);
}

func();
func.call(null);
func.apply(undefined);
func.bind({})();

在 Sloppy Mode 分別以 call()apply()bind() 執行 Function Declaration。

this004

outerThiswindow

  1. 在 Sloppy Mode 下,Function Declaration 的 thiswindow,因此為 true
  2. 在 Sloppy Mode 下,Function Declaration 的 call() 若傳入 null,不會影響 this,一樣是 windows,因此為 true
  3. 在 Sloopy Mode 下, Function Declaration 的 apply() 若傳入 undefined,不會影響 this,一樣是 window,因此為 true
  4. 在 Sloopy Mode 下,Function Declaration 的 bind() 若傳入 nullundefined 以外的值,如 empty object {}this 變成 {},因此為 false

Strict Mode

1
2
3
4
5
6
7
8
9
10
11
12
"use strict";

const outerThis = this;

function func() {
console.log(this === outerThis);
}

func();
func.call(null);
func.apply(undefined);
func.bind({})();

在 Strict Mode 分別以 call()apply()bind() 執行 Function Declaration。

bind004

outerThiswindow

  1. 在 Strict Mode 下,Function Declaration 的 thisundefined,因此為 false
  2. 在 Strict Mode 下,Function Declaration 的 call() 若傳入 null,不會影響 this,一樣是 undefined,因此為 false
  3. 在 Strict Mode 下, Function Declaration 的 apply() 若傳入 undefined,不會影響 this,一樣是 undefined,因此為 false
  4. 在 Strict Mode 下,Function Declaration 的 bind() 若傳入 nullundefined 以外的值,如 empty object {}this 變成 {},因此為 false

無論在 Sloppy Mode 或 Strict Mode 下,call()apply()bind() 傳入 nullundefined都不會改變 this

Anonymous Function


Sloppy Mode

1
2
3
4
5
6
7
8
9
10
const outerThis = this;

const func = function() {
console.log(this === outerThis);
};

func();
func.call(null);
func.apply(undefined);
func.bind({})();

在 Sloppy Mode 分別以 call()apply()bind() 執行 Anonymous Function。

bind005

outerThiswindow

  1. 在 Sloppy Mode 下,Anonymous Function 的 thiswindow,因此為 true
  2. 在 Sloppy Mode 下,Anonymous Function 的 call() 若傳入 null,不會影響 this,一樣是 window,因此為 true
  3. 在 Sloopy Mode 下, Anonymous Function 的 apply() 若傳入 undefined,不會影響 this,一樣是 window,因此為 true
  4. 在 Sloopy Mode 下,Anonymous Function 的 bind() 若傳入 nullundefined 以外的值,如 empty object {}this 變成 {},因此為 false

Strict Mode

1
2
3
4
5
6
7
8
9
10
11
12
"use strict"

const outerThis = this;

const func = function() {
console.log(this === outerThis);
};

func();
func.call(null);
func.apply(undefined);
func.bind({})();

在 Strict Mode 分別以 call()apply()bind() 執行 Anonymous Function。

bind006

outerThiswindow

  1. 在 Strict Mode 下,Anonymous Function 的 thisundefined,因此為 false
  2. 在 Strict Mode 下,Anonymous Function 的 call() 若傳入 null,不會影響 this,一樣是 undefined,因此為 false
  3. 在 Strict Mode 下, Anonymous Function 的 apply() 若傳入 undefined,不會影響 this,一樣是 undefined,因此為 false
  4. 在 Strict Mode 下,Anonymous Function 的 bind() 若傳入 nullundefined 以外的值,如 empty object {}this 變成 {},因此為 false

Function Declaration 與 Anonymous Function 對於 call()apply()bind()this 的影響都是一樣的,無論是 Sloppy Mode 或 Strict Mode

Arrow Function


Sloppy Mode

1
2
3
4
5
6
7
8
9
10
const outerThis = this;

const func = () => {
console.log(this === outerThis);
};

func();
func.call(null);
func.apply(undefined);
func.bind({})();

在 Sloppy Mode 分別以 call()apply()bind() 執行 Arrow Function。

bind007

outerThiswindow

  1. 在 Sloppy Mode 下,Arrow Function 的 this 為 parent scope 的 window,因此為 true
  2. 在 Sloppy Mode 下,Arrow Function 的 call() 無論傳入什麼都不會改變 this,一樣是 window,因此為 true
  3. 在 Sloopy Mode 下, Arrow Function 的 apply() 無論傳入什麼都不會改變 this,一樣是 window,因此為 true
  4. 在 Sloppy Mode 下,Arrow Function 的 bind() 無論傳入什麼都不會改變 this,一樣是 window,因此為 true

Strict Mode

1
2
3
4
5
6
7
8
9
10
11
12
"use strict";

const outerThis = this;

const func = () => {
console.log(this === outerThis);
};

func();
func.call(null);
func.apply(undefined);
func.bind({})();

在 Strict Mode 分別以 call()apply()bind() 執行 Arrow Function。

bind008

outerThiswindow

  1. 在 Strict Mode 下,Arrow Function 的 this 為 parent scope 的 window,因此為 true
  2. 在 Strict Mode 下,Arrow Function 的 call() 無論傳入什麼都不會改變 this,一樣是 window,因此為 true
  3. 在 Strict Mode 下, Arrow Function 的 apply() 無論傳入什麼都不會改變 this,一樣是 window,因此為 true
  4. 在 Strict Mode 下,Arrow Function 的 bind() 無論傳入什麼都不會改變 this,一樣是 window,因此為 true

無論是 call()apply()bind(),甚至於 Sloppy Mode 或 Strict Mode,都無法改變 this

Conclusion


  • 在 Sloppy Mode 的 Function Declaration 或 Anonymous Function,thiswindow
  • 在 Strict Mode 的 Function Declaration 或 Anonymous Function,thisundefined
  • 無論在 Sloppy Mode 或 Strict Mode,Arrow Function 的 this 皆為 parent scope window
  • 無論在 Sloppy Mode 或 Strict Mode,將 nullundefined 透過 call()apply()bind() 傳入 Function Declaration 或 Anonymous Function,皆無法改變 this
  • 無論在 Sloppy Mode 或 Strict Mode,都無法透過 call()apply()bind() 改變 Arrow Function 的 this

Reference


Egghead.io, Understanding JavaScript’s this Keyword in Depth

2018-11-24