JavaScript 中 this 關鍵字的作用和如何改變其上下文

2023-01-21 15:00:12

一、this 關鍵字的作用

JavaScript 中的 this 關鍵字參照了所在函數正在被呼叫時的物件。在不同的上下文中,this 的指向會發生變化。

在全域性上下文中,this 指向全域性物件(在瀏覽器中是 window 物件,在 Node.js 中是 global 物件)。

在函數中,this 指向呼叫該函數的物件。如果該函數是通過物件的方法呼叫的,那麼 this 指向該物件;如果是通過函數呼叫的,那麼 this 指向全域性物件。

在箭頭函數中,this 繼承自父級作用域中的 this

在類別建構函式中,使用 new 關鍵字呼叫類時,this 指向新建立的物件。

例如:

class MyClass {
  constructor() {
    this.value = 42;
  }
}

let obj = new MyClass();
console.log(obj.value); // 42

類的實體方法中的 this 預設指向範例本身,類方法中的 this 預設指向類本身

例如:

class MyClass {
  value = 42;
  printValue() {
    console.log(this.value);
  }
  static printValue() {
    console.log(this.value);
  }
}

let obj = new MyClass();
obj.printValue(); // 42
MyClass.printValue(); // undefined

使用 Object.create 方法建立物件

使用 Object.create 方法建立是一種特殊的呼叫方式。在這種情況下,如果在物件的原型鏈上呼叫函數,則 this 指向該物件。

例如:

let baseObject = { value: 42 };
let obj = Object.create(baseObject);

function printValue() {
  console.log(this.value);
}

printValue.call(obj); // 42

這種情況下, obj 的原型鏈上有 value 屬性,所以呼叫 printValue() 方法時, this 指向 obj 物件。

在類中使用箭頭函數

類中使用箭頭函數定義的方法中的 this 指向是繫結的,它指向的是類的範例,而不是類本身。

例如:

class MyClass {
  value = 42;
  printValue = () => {
    console.log(this.value);
  }
}
let obj = new MyClass();
obj.printValue(); // 42

箭頭函數的 this 是定義時的 this,而不是呼叫時的 this。因此,在類中使用箭頭函數可以避免在方法中使用 bind 來繫結 this

在呼叫建構函式時,未使用 new 關鍵字

在這種情況下,this 指向全域性物件。這種情況下不會建立新的物件,而是改變了全域性物件的狀態。

例如:

class MyClass {
  constructor() {
    this.value = 42;
  }
}

let obj = MyClass(); // without new keyword
console.log(obj); // undefined
console.log(value); // 42

因此,在使用建構函式建立物件時,需要確保使用 new 關鍵字來呼叫建構函式,否則可能會導致意外的結果。

在使用建構函式時特別需要注意使用 new 關鍵字來呼叫。

在物件的方法中使用箭頭函數會導致 this 指向問題

例如:

let obj = {
  value: 42,
  printValue: () => {
    console.log(this.value);
  }
};
obj.printValue(); // undefined

這種情況下,在 obj 物件的 printValue 方法中使用了箭頭函數,而箭頭函數的 this 指向是定義時的 this,而不是呼叫時的 this。在這種情況下,因為箭頭函數的 this 指向是定義時的 this,所以 this.value 指向的是 undefined,而不是 obj 物件中的 value。

解決這種問題可以使用箭頭函數的父級作用域中的 this,或者使用普通函數來解決。

例如:

let obj = {
  value: 42,
  printValue: function(){
    console.log(this.value);
  }
};
obj.printValue(); // 42

或者

let obj = {
  value: 42,
  printValue: () => {
    console.log(obj.value);
  }
};
obj.printValue(); // 42

在物件的方法中使用箭頭函數會導致 this 指向問題,需要特別注意。可以使用箭頭函數的父級作用域中的 this 或者普通函數來解決。

總之,JavaScript 中的 this 關鍵字指向的上下文取決於函數的呼叫方式,需要根據不同的場景來選擇合適的方式來改變 this 的指向

二、如何改變 this 上下文

可以通過 call, apply, bind 方法來改變 this 的上下文。

callapply 方法允許您將函數的 this 指向指定的物件,並立即執行該函數。

call 方法的語法格式如下:

functionName.call(thisArg, arg1, arg2, ...);

apply 方法的語法格式如下:

functionName.apply(thisArg, [arg1, arg2, ...]);

bind 方法允許您將函數的 this 指向指定的物件,但不立即執行函數,而是返回一個新函數,可以在將來執行。

let newFunc = functionName.bind(thisArg, arg1, arg2, ...);

例如:

let obj = {value: 42};

function printValue() {
  console.log(this.value);
}

printValue.call(obj); // 42
printValue.apply(obj); // 42
let boundFunc = printValue.bind(obj);
boundFunc(); // 42

總之,通過使用 call, apply, bind 方法,可以改變函數中的 this 指向,從而在不同的上下文中使用同一個函數。