iT邦幫忙

0

Javascript 進階 5-7 this:簡易呼叫

這個章節要來介紹 簡易呼叫(Simple Call)

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

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

callName();

可以看到這是上一篇文章的範例,並且在這裡 callName(); 就是典型的 簡易呼叫(Simple Call)

並且要特別提醒!

盡可能不要使用 簡易呼叫(Simple Call) 的 this

原因呢我們後面會提到,我們先接著看下面的範例:

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

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

// IIFE
(function () {
    console.log(this.myName);
    function callSomeone () {
        console.log(this.myName);
    }
    callSomeone();
})();

首先我們利用一個立即函式包住 console.log(this.myName); 這裡的這個 this.myName 因為沒有在立即函式的內部定義,所以會指向外層的 真心鎮大冒險。

然後我們在這個裡面又訂一個另外一個函式 callSomeone,並且立刻執行他。

所以在這裡呢,callSomeone(); 也是一個典型的 簡易呼叫(Simple Call)。

所以這裡的 this 也是指向全域的 window 物件。

在這邊提醒大家~之前有提過一個概念就是

所謂的全域變數都是掛在 window 這個物件下,所以很多人會以為我們執行 簡易呼叫(Simple Call) 的時候,會是 window.callSomeone() 的感覺。

但其實並不是這樣的概念,下一篇文章會再詳細說明這個部分。

簡單來說重點就是

  1. 只要看到直接執行的呼叫句就是 簡易呼叫(Simple Call)。
  2. window.callSomeone() 的執行方式並不是 簡易呼叫(Simple Call)。
  3. 簡易呼叫(Simple Call)的 this 指向的全域的物件 window。

了解了這些以後我們繼續往下~

之前我們有討論到閉包的狀況,調用函式中回傳的函式,也是屬於 簡易呼叫(Simple Call) 的一種。

var myName = '真心鎮大冒險';
function easyCard (base) {
    var money = base;
    var name = '悠遊卡';
    return function (update) {
        money = money + update;
        console.log(this.myName, money);
    }
}
var MingEasyCard = easyCard(100);
MingEasyCard(10);

https://ithelp.ithome.com.tw/upload/images/20200130/20121770AHisfcQgo1.png

執行上述的程式碼,可以看到 this.myName 的指向還是全域的 '真心鎮大冒險'。

這邊就得證 MingEasyCard(10); 也是 屬於 簡易呼叫(Simple Call) 的一種。

再來討論 callBack 的狀況

callback就是將一個函式傳到另一個函式內,並且在另外一個函式內執行。

那麼,再另一個函式裡面執行的形式,也是屬於 簡易呼叫(Simple Call) 喔!

那麼一樣這邊的 this 指向的就是全域 window。

var myName = '真心鎮大冒險';
function myEasyCard (callback) {
    var money = 100;
    return callback(money);
}

myEasyCard(function (money) {
    console.log(this.myName, money + 100);
});

所以結果印出來就會是 真心鎮大冒險 200

https://ithelp.ithome.com.tw/upload/images/20200130/20121770dHSMHkwVIb.png

除了我們這邊寫的這個之外呢,還有就是 forEach 的例子

var myName = '真心鎮大冒險';
var a = [1, 2, 3];
a.forEach(function (i) {
    console.log(this.myName, i);
});

這樣執行了以後呢,會得到下面的結果:

https://ithelp.ithome.com.tw/upload/images/20200130/20121770VRJxiNzQ8l.png

所以 callback function 也是屬於 簡易呼叫(Simple Call) 喔!

其 this 的指向會指向到 window 物件。

再來就是最後一個範例:

var myName = '真心鎮大冒險';
var family = {
    myName: '小明家',
    callName: function () {
        setTimeout(function () {
            console.log(this.myName);
        }, 1000);
    }
}
family.callName();

請問這樣console.log印出來會是 真心鎮大冒險 還是 小明家 呢?

https://ithelp.ithome.com.tw/upload/images/20200130/20121770IDrczbIUhF.png

答案如上,印出來是 真心鎮大冒險。

原因是因為,雖然執行的方式是在 family 下執行,的確callName裡面執行環境的指向是family的物件。

但是在那裏面又包了一個setTimeout的執行環境,傳入的是 callback function,所以 callback function 裡面的 this 指向就還是全域的 window物件。

所以答案就是 真心鎮大冒險喔!

但是,如果我今天就是要取得family這個物件裡面的 myName,也就是 小明家 的話,我該怎麼做呢?

很簡單,只需要先在 callName的執行環境中,把this保存再某一個變數裡面,並且替換 this => 變數名稱 就可以了喔!

程式碼如下:

var myName = '真心鎮大冒險';
var family = {
    myName: '小明家',
    callName: function () {
        var self = this;
        setTimeout(function () {
            console.log(self.myName);
        }, 1000);
    }
}
family.callName();

這樣子執行的結果就會印出小明家了

https://ithelp.ithome.com.tw/upload/images/20200130/20121770kvNXLQdy5D.png

其中乘載 this 的變數名稱通常會被叫做 self、vm、that等,依據不同的開發環境會有不同的命名習慣。

好~那麼這篇文章主要就是介紹 簡易呼叫(Simple Call),如果沒有問題的話,我們就繼續往下一篇文章邁進吧!


尚未有邦友留言

立即登入留言