this

this 的兩個大原則

  • Call function 時, 若沒有透過任何物件, 指向 window (in browser)
1
2
3
4
5
function a(){
console.log(this);
}

a(); // Output: 'window' (當執行環境為browser時)
  • Call function 時, 透過物件, 則指向當下 call它的物件
1
2
3
4
5
6
7
8
9
10
11
function func() {
console.log(this.x);
}

let obj = {
x: 100
}

obj.func = func;

obj.func(); // Output : 100 .
1
2
3
4
5
6
7
8
9
10
11
let obj = {
x: 20,
f: function(){ console.log(this.x); }
};

obj.innerobj = {
x: 30,
f: function(){ console.log(this.x); }
}

obj.innerobj.f(); // 由於調用f函式時,點前面物件為obj.innerobj,故f內的this指向obj.innerobj,則輸出為30。

透過 .call() , .apply() 來指定 this

1
2
3
4
5
6
7
8
9
10
11
12
let obj = {
x: 100,
func: function() {
console.log(this.x);
}
}

let obj2 = {
x: 200
}

obj.func.call(obj2); // func的this被指定為 obj2, 故Output : 200 .

函數建構子搭配 new 建立物件

  • 利用函數建構子建立物件時, 該函數內的 this 會指向當下建立的新物件 .
1
2
3
4
5
6
function Obj(x, y) {
this.x = x; // 這兩個this都是指向 a 這個新物件 .
this.y = y;
}

let a = new Obj(x,y);

API 中 Callback function 中的 this

  • 在這些情況中, 大多在底層有經過特殊處理 (e.g. 利用.call()來直接指定適當的this)
1
2
3
4
$('#mybtn').addEventListener('click', function() {
console.log(this);
// 這裡的this指向所選到的button物件, 即在API底層經過 [我們所撰寫的callback].call([button物件]) .
})

Node 環境中的 this

  • 利用 cmd: node [filename] 來執行 js 檔案的情況下, 在 node 的 global 環境宣告變數時, 不會掛載在其 global 物件上(不像 browser 會掛在 window 上), 因此在測試時需注意
    1
    2
    3
    4
    5
    6
    let x = 100;
    function a() {
    console.log(this.x);
    }

    a(); // Output: undefined .

ES6 Arrow function 中的 this

  • ES6中, Arrow function 是沒有 this 的, 因此, 在 Arrow function 中使用 this, 會繼承其創建時function scope 所對應的 this
  • 沒有this, 所以不可以當建構子函數
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Sample 1.
let Person = {
name: "Ricky",
sayHi: () => {
// 此時 this 是指向 window
// Person 物件非 function, 本身不是一個 Scope, 所以再指向外面那層, 即 window
console.log(`Hi ${this.name}`);
}
}

Person.sayHi(); // Ouput: Error

// Sample 2.
let Person = {
name: "Ricky",
age: 22,
intor: function() {
let sayHi = () => {
// 此時 this 是指向 Person
// 在這個 intro function 的 scope 內的 this 是 Person
console.log(`${this.name} ${this.age}!`);
}
sayHi();
}
}

常出現的陷阱

1
2
3
4
5
6
7
8
9
10
var c = {
name: 'The c object',
log: function() {
var log2 = function() {
console.log(this);
}
log2();
}
}
c.log(); // 顯示 window
  • 解決方法 :

    • ES5

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      var c = {
      name: 'The c object',
      log: function(){
      var self = this; //建立一個變數 self 把這邊的 this 存起來
      var log2 = function(){
      console.log(self);
      }
      log2();
      }
      }

      c.log(); // 顯示 Object {name: "The c object"}
    • ES6 - arrow function

參考文獻