前言
盡可能不要使用簡易呼叫 (Simple Call) 的 this
簡易呼叫
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() 這樣呈現,但其實並不是這樣的概念,下一篇文章會再詳細說明這個部分。
簡單來說重點就是
- 只要看到直接執行的呼叫句就是簡易呼叫 (Simple Call)
window.callSomeone()的執行方式並不是簡易呼叫 (Simple Call)- 簡易呼叫 (Simple Call) 的
this指向的全域的物件window
閉包,調用函式中回傳的函式,也是屬於簡易呼叫的一種
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);
執行上述的程式碼,可以看到 this.myName 的指向還是全域的 '真心鎮大冒險',這邊就得證 MingEasyCard(10);
也是屬於簡易呼叫的一種。
callBack,也是屬於簡易呼叫
callback 就是將一個函式傳到另一個函式內,並且在另外一個函式內執行。
那麼,在另一個函式裡面執行的形式,也是屬於簡易呼叫,這邊的 this 指向的就是全域 window
var myName = '真心鎮大冒險';
function myEasyCard (callback) {
var money = 100;
return callback(money);
}
myEasyCard(function (money) {
console.log(this.myName, money + 100);
});
結果印出來就會是 '真心鎮大冒險', 200
除了我們這邊寫的這個之外呢,還有就是 forEach 的例子
var myName = '真心鎮大冒險';
var a = [1, 2, 3];
a.forEach(function (i) {
console.log(this.myName, i);
});
執行後會得到下面的結果:
所以 callback function 也是屬於簡易呼叫,其 this 的指向會指向到 window 物件
再來看最後一個範例:
var myName = '真心鎮大冒險';
var family = {
myName: '小明家',
callName: function () {
setTimeout(function () {
console.log(this.myName);
}, 1000);
}
}
family.callName();
請問這樣 console.log 印出來會是 '真心鎮大冒險' 還是 '小明家' 呢?
答案是 '真心鎮大冒險'
原因是因為,雖然執行的方式是在 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();
這樣子執行的結果就會印出 '小明家' 了
其中乘載
this的變數名稱通常會被叫做self、vm、that等,依據不同的開發環境會有不同的命名習慣