切換語言為:簡體

理解JavaScript 中的難點: this關鍵字

  • 爱糖宝
  • 2024-10-16
  • 2035
  • 0
  • 0

今天我在學習手寫 Promise 的過程中又遇到了 this。說實話,作為從業三年的開發者,this 一直是個讓我頭疼的問題,尤其對於我這個用了三年的 React 函式式元件的人來說,this 的指向總是變來變去。我常常困惑於它到底指向了什麼、為什麼要用它。可是,當我嘗試繼續深入理解 Promise 時,發現繞不開 this 這個概念。沒辦法,只能硬著頭皮學下去了。既然如此,我們就一起來揭開這個在 JavaScript 中根深蒂固的“謎題”。

this 是 JavaScript 中一個複雜且重要的概念,它的指向是動態的,取決於函式的呼叫方式。要徹底理解 this,我們需要深入瞭解它在不同場景下的表現。接下來,我將透過幾個不同的例子幫助你全面理解 this 的使用。

1. 普通函式中的 this

在普通函式中,this 的指向取決於誰呼叫了這個函式,它在呼叫階段動態繫結。例如:

function showThis(){
  console.log(this);  // 瀏覽器中是 window,Node.js 中是 global
}
showThis();

在這個例子中,showThis 是在全域性環境中執行的,相當於全域性環境呼叫了這個函式,因此 this 的指向是全域性物件。

如果在物件的方法中呼叫函式,呼叫者是該物件,那麼 this 的指向就是該物件:

const obj = {
    a: 1,
    b: function(){
        console.log(this.a);  // 輸出 1
    }
}
obj.b();

注意:在嚴格模式 ('use strict') 下,如果 this 沒有顯式繫結,它的指向會是 undefined

'use strict';
function showThis(){
  console.log(this);  // 輸出 undefined
}
showThis();

2. 箭頭函式中的 this

箭頭函式與普通函式不同,它的 this 在定義時就已經確定了。箭頭函式不會建立自己的 this,而是繼承自定義時所在的作用域。看看下面的例子:

function Outer(){
    this.name = 'outer';
    
    const regularFunction = function(){
        console.log(this.name);  // 非嚴格模式下為 undefined,嚴格模式下同樣為 undefined
    }

    const arrowFunction = () => {
        console.log(this.name);  // 輸出 'outer'
    }

    regularFunction();
    arrowFunction();
}

new Outer();

在這個例子中,箭頭函式 arrowFunction 繼承了 Outer 的作用域,因此 this 指向 Outer 的例項。而普通函式 regularFunction 沒有繼承 Outerthis,所以 this.name 輸出 undefined

物件中的箭頭函式也是類似的:

const obj = {
    a: 1,
    b: function(){
        const output = () => {
            console.log(this.a);  // 輸出 1
        }
        output();
    }
}
obj.b();

在這個例子中,箭頭函式 output 繼承了 b 方法的 this,因此 this.a 輸出的是 obj.a

3. 顯式繫結:callapplybind

上面提到的例子都是隱式繫結,即 this 自動繫結到呼叫者。接下來我們看看顯式繫結,即透過 callapplybind 來手動控制 this 的指向。

1. call()apply()

callapply 都會立即呼叫函式,它們的區別在於引數傳遞方式不同:

  • call:引數以逗號分隔傳遞。

  • apply:引數以陣列形式傳遞。

例如:

function greet(greeting, punctuation) {
    console.log(greeting + ', ' + this.name + punctuation);
}

const person = { name: 'Bob' };

greet.apply(person, ['Hi', '.']);  // 輸出 "Hi, Bob."
greet.call(person, 'Hello', '!');  // 輸出 "Hello, Bob!"

2. bind()

bindcallapply 不同,它不會立即呼叫函式,而是返回一個新函式,這個新函式的 this 永遠繫結到 bind() 的第一個引數。你可以傳遞引數給 bind(),這些引數會在呼叫新函式時依次傳入。

例如:

function greet(greeting, punctuation) {
  console.log(greeting + ', ' + this.name + punctuation);
}

const person = { name: 'Charlie' };

// 使用 bind 建立一個新的函式,this 永遠繫結到 person
const boundGreet = greet.bind(person, 'Hey');

// 呼叫繫結的函式
boundGreet('!!');  // 輸出 "Hey, Charlie!!"


總結

this 是 JavaScript 中一個動態的概念,它的指向取決於函式的呼叫方式。在普通函式中,this 的指向取決於誰呼叫了該函式;而在箭頭函式中,this 會繼承定義時的上下文。此外,透過 callapplybind,我們可以顯式地控制 this 的指向。理解 this 是掌握 JavaScript 高階特性的關鍵,尤其是在編寫複雜的非同步程式碼和元件庫時。


透過這些場景的例子,你應該能夠更好地理解 this 在 JavaScript 中的表現,進而更加自信地在專案中使用它!

0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.