0%

JS核心-(38)-函式以及This的運作-最常見的 this:物件的方法調用

前言

this 是讓很多開發者頭痛的地方,這篇文章會用簡單的方式讓大家知道,this 現在到底是誰 !

this 是 function 被執行的時候自帶的變數

var myName = '真心鎮大冒險';

function callName () {

}

callName();

我們先這樣執行以後,打開 chrome 的開發者人員工具,然後選擇 Source 的 Tag,按下這個暫停的按鈕

重新整理之後呢,我們來進入這個函式的執行堆疊

接著我們進入這個函式的執行堆疊之後,你就會發現 this 居然一開始就存在了

也就是說就算不做任何事,只要函式的作用域一創建,就會有 this 這個變數。

而現在圖片中的例子呢,this 是指向全域的物件 window


而這個 this 的指向規則,跟我們怎麼去呼叫這個函式有很大的關聯性

我們先稍微調整一下程式碼

var myName = '真心鎮大冒險';

function callName () {
    console.log(this.myName);
}

callName();  // 真心鎮大冒險

所以透過上方的例子你只需要了解到兩件事

  • this 是 function 被執行的時候自帶的變數
  • this的指向跟函式的呼叫有關

this

this 是我們在執行函式的時候它自然就會產生,不需要特別的去宣告它,就是一個保留的關鍵字。不管是在全域的環境下,

還是特定的函式中,你都可以直接調用 this,因為 this 在每個執行環境都會存在,所以很多人會誤認為 this 就是指向函式

本身。

其實函式本身能夠提供的屬性有限,那通常來說我們並不會使用 this 去調用函是本身,而 this 通常是指向一個可以被調用

的物件,所以大家不要誤認為 this 就是指向函式本身。


this基本觀念

  • 每個執行環境都有屬於自己的 this 關鍵字
  • this與函式如何宣告沒有關聯性,僅與呼叫方法有關
  • 嚴格模式下,簡易呼叫會有很大的改變

那麼我們剛剛就有說到,this 的指向跟函式的呼叫有關


影響 this 的調用方式有哪些

  • 作為物件方法 (最常運用 this 方法)

這篇文章的觀念你只要掌握,通常 this 有 8 成都是運用到這個觀念

  • 簡易呼叫 (絕大多數的呼叫方式)

這個是最常見的函式呼叫方式,但是要注意,簡易呼叫不建議用運用它的 this
在這篇文章中也會介紹什麼是簡易呼叫?以及為什麼要避免運用簡易呼叫的 this

  • bind、apply、call 方法

是綁定函式到特定的 this 的方法

  • new

建構式的運算子,我們之後會在原形的章節介紹到

  • DOM 事件處理器

陸續會介紹到

  • 箭頭函式 ES6

陸續會介紹到


this 到底有甚麼用呢?

也就是可以透過 this 指向前面的物件。

而這邊要介紹,其實物件的方法調用 (As an object method) 是最常見的形式,這邊也是要記住兩個重點:

  • this與函式如何宣告沒有關聯性,僅與呼叫方法有關
  • 物件的方法調用時,僅需要關注是在哪一個物件下呼叫

也就是說使用物件的方式調用的時候,你只需要關注它是在哪個物件下調用的就好 !

以下面的例子來說:

基本上這樣執行函式的時候,後面的函式的 this 就是指向前面這個物件。


接下來我們來看一下範例

範例 1

var myName = '真心鎮大冒險';

function callName () {
    console.log(this.myName);
}

var family = {
    myName: '小明家',
    callName: callName
}

family.callName(); // 小明家

在這裡我們不管 callName 這個函式是怎麼定義的,我們只 care 它是在哪個物件下被呼叫。因此這個 this 現在就是指向

family 這個物件,所以很明顯透過 callName的函式印出來的結果是 '小明家'

也可以多修改一下程式碼,看看 this 現在是指向誰

var myName = '真心鎮大冒險';

function callName () {
    console.log(this, this.myName);
}

var family = {
    myName: '小明家',
    callName: callName
}

family.callName();

範例2

var myName = '真心鎮大冒險';

function callName () {
    console.log(this, this.myName);
}

var family = {
    myName: '小明家',
    callName: callName,
    Ming: {
        myName: '小明',
        callName: callName,
    }
}

family.callName();
family.Ming.callName();

很明顯 family.callName(); 跟剛剛一樣就會印出 '小明家' ,但第二個 family.Ming.callName(); 這個 this 指向的就是

Ming 這個物件,所以印出來的就會是 '小明'

範例3

var myName = '真心鎮大冒險';

function callName () {
    console.log(this.myName);
}

var family = {
    myName: '小明家',
    callName: function () {
        console.log(this.myName);
    }
}

family.callName(); // 小明家

var callName = family.callName;

callName(); // ?

這邊我們可以看到 family.callName(); 這段的邏輯就是跟上面一樣, this 指向 family 的物件。

那麼如果我們今天把 family.callName 重新命名一個變數,然後在執行這個變數的話?

現在 this 會指向誰呢 ?

.
.
.
.
.

執行的結果就是 '真心鎮大冒險'

為什麼會這樣呢?

因為它被執行在全域的情況下,它的 this 就指向到了 window 的物件,所以它 console.log 出來的結果就會是 '真心鎮大冒險'