上次更新: 2024-06-18
this 的值取決於函式是如何被調用的this 代表的就是呼叫函式的物件this 的情況下,this 預設為全域物件(也就是 window)白話點來說, this 代表的是函式執行時所屬的物件,並且它的值並不是固定的,而是取決於函式被呼叫的方式及環境。
以下是一些常見的情況和對應的 this 值
在全域環境中,this 指向全域物件。
在瀏覽器中,這個全域物件就是是 window,在 Node.js 中則是 global。
console.log(this); // 會印出 window 物件在普通函式調用中,this 在非嚴格模式會是 window ,在嚴格模式會是 undefined。
function foo() {
'use strict';
console.log(this);
}
foo(); // undefined
function bar() {
console.log(this);
}
bar(); // window當函式作為物件的方法來調用時,this 指向調用該方法的物件。
在下面範例中,printName 是物件 obj 底下的方法,因此 this 會指向 obj。
const obj = {
name: 'Iris',
printName: function () {
console.log(this.name);
},
};
obj.printName(); // Iris再一個範例:
以下程式碼會印出什麼呢?
var myName = 'Global name';
function print() {
console.log(this.myName);
}
const obj = {
printName: print,
};
obj.printName();答案是:undefined
前面有說了,this 代表的是函式執行時所屬的物件,printName 執行時所屬的物件是 obj,而 obj 並沒有 myName 屬性。
箭頭函式沒有自己的 this,它的 this 會等於被宣告當下所在環境的 this。
我們把前一個範例稍微改寫一下,將 print 改成箭頭函式寫法,結果會如何呢?
var myName = 'Global name';
const print = () => {
console.log(this.myName);
};
const obj = {
printName: print,
};
obj.printName();答案:Global name
因為箭頭函式的 this 會指向它宣告當下所在環境,因此會印出 Global name
當使用 new 呼叫建構函式時,this 會指向新創建的物件。
它的步驟如下:
[[prototype]] 屬性設置為建構函式的 prototype 屬性。function Person(name, age) {
this.name = name;
this.age = age;
console.log(this);
}
const greta = new Person('Greta', 30);console.log(this) 結果會如下:
Person {
name: "Greta",
age: 30
}接下來是幾個判斷 this 值的練習題:
const foo = function () {
this.count++;
};
foo.count = 0;
for (let i = 0; i < 5; i++) {
foo();
}
console.log(foo.count);答案:0
在 foo() 執行時,this 都是指向 window 物件,因此 foo 裡面的 this.count 其實是 window.count;而 foo.count 從頭到尾都沒有變動。
function bar() {
console.log(this.a);
}
function foo() {
const a = 123;
this.bar();
}
foo();答案:undefined
foo 的 this 是指向 window,因此 this.bar 實際上是 window.bar,而 window 並沒有 a 數性,因此會印出 undefined。
補充:
在 Javascript 中,當我們在全域範圍內定義一個 var 或 function,它會自動成為全域物件(也就是 window)的屬性,所以可以用 window.bar 來做調用。
如果把上面範例的 function bar 改成用 const 或 let 來定義,就無法使用 window.bar 了。
在前面 3.使用物件來調用 跟 4.箭頭函式 兩個例子中,是使用 var 來宣告變數,也是同樣的原因。
const obj = {
func1: function () {
console.log(this === obj);
const func2 = function () {
console.log(this === obj);
};
func2();
},
};
obj.func1();答案:
true
false
func1 會印出 true,應該很好理解,因為 func1 是作為 obj 的方法來呼叫,因此 this 指向 obj 物件。
那為何 func2 是 false 呢?
因為即使把 func2 寫在 obj 裡,但它並不是作為 obj 的方法來呼叫的。因此 func2 裡面的 this 並不會自動指向 obj,而是預設的 window 物件。
const obj1 = {
count: 10,
doSomethingLater() {
setTimeout(function () {
this.count++;
console.log(this.count);
}, 300);
},
};
obj1.doSomethingLater();
const obj2 = {
count: 10,
doSomethingLater() {
setTimeout(() => {
this.count++;
console.log(this.count);
}, 300);
},
};
obj2.doSomethingLater();答案:
NaN
11
obj1 的 setTimeout 裡面的 callback 並不是由 obj1 呼叫的,因此 this 指向 window,而在 windonw 中沒有 count,所以答案是 NaNobj2 的 setTimeout 裡面的是箭頭函式,它的 this 值是被宣告當下作用域的 this,因此會是最接近的父層一般函式的 this 值,也就是 2obj2,原本 count 為 10,10++ 後變成 11const obj = {
name: 'Alice',
sayHello() {
console.log(this.name);
},
};
setTimeout(obj.sayHello, 1000);答案:
undefined
因為 setTimeout(obj.sayHello, 1000) 其實等同於:
const fn = obj.sayHello;
setTimeout(fn, 1000); // `fn()` 被當作一般函式執行參考資料