iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 22
0
Modern Web

【這些年我似是非懂的 Javascript】系列 第 22

【這些年我似是非懂的 Javascript】Day 22 - 是這個不是那個的 this # Part 2.

  • 分享至 

  • xImage
  •  

接續昨天的內容讓我們繼續看下去~

呼叫地點

昨天提到

其實就是當一個函式被調用時會有一個"啟動紀錄"被創建出來,也被叫做"執行情境",他裡面就包含了很多資訊包含該函式式在哪裡被調用的傳入什麼參數等等的,

所以...
我們找是誰調用他的就可以找到該函式被調用的位置,
真簡單~

這世界...
沒有你想的那麼簡單,某些編成模式會遮蔽真正調用的位置。

呼叫堆疊

到底是誰叫了我?
他就是執行到目前為止已被呼叫的函式所產生的堆疊,
不用想太多就是一個堆疊然後一直紀錄誰叫了誰這樣。

function baz(){
    // 堆疊: baz 所以被呼叫的地點是在全域範疇中
    console.log("baz");
    bar();
}

function bar(){
    // 堆疊: baz -> bar 所以被呼叫的地點是在 baz
    console.log("bar");
    foo();
}

function foo(){
    // 堆疊: baz -> bar -> foo 所以被呼叫的地點是在 bar
    console.log("foo");
}

baz(); // 起始點

這樣看起來其實呼叫堆疊沒你想像的那麼難對吧!?
一片蛋糕!

就像是你高中學的程式追蹤一樣~

規則

在知道上面的被誰呼叫之後,接著就要開始判斷 this 中的四個規則。

  • 預設繫結
  • 隱含的繫結
  • 隱含地失去
  • new 繫結

預設繫結

這是第一個規則也是最常見的規則,
獨立函式的調用

function foo(){
    console.log(this.a);
}

var a = 2;
foo(); // 2

其實 foo 裡面的 this.a 就等於外面的 a,他並不是拷貝出來的而是真的他!

但是凡事都有例外
在嚴格模式(strict mode)中全域物件就不會是預設繫結this 就會變成 undefined

function foo(){
    "use strict"
    console.log(this.a);  
}

var a = 2;
foo(); // TypeError 因為 this 是 undefined

主要嚴格模式會影響的其實是該函式,跟調用的地點無關

function foo(){
    console.log(this.a); // 沒事兒
}

var a = 2;

(function(){
    "use strict"
    
    foo(); // 2
})();

書中溫馨提醒:
不要混合使用 strict mode 和不是 strict mode,是男人就整個都用或是都不要用,不然會讓人黑人問號。

隱含的繫結

呼叫地點如果是一個...
情境物件(context object)
擁有物件(owning object)
包含物件(containing object)
以上三個都是一樣的東西只是名詞不一樣

反正長得像這樣

function foo(){
    console.log(this.a); // 叫的是 obj 的 a ,不是全域的 a 
}

var obj = {
    a:2,
    foo:foo
};

var a = 6;

obj.foo(); //2

剛剛說的那三個名詞聽起來就是 obj "擁有"了這個函式,所以導致 this 指向該物件。
...

...

...

你只能說他在呼叫的"那時候"擁有或包含那個函式。

不在乎天長地久,只在乎曾經擁有

(不要理我,讓我尷尬

這部分很簡單的是假如包了又包包了又包,那到底是指誰!?
就是最後誰指誰就是誰!

function foo(){
    console.log(this.a);
}

var obj = {   // 最後的一根稻草
    a:2,
    foo:foo
};

var obj1 ={
    a: 12,
    obj:obj
}

var a = 6;

obj1.obj.foo(); //2

隱含地失去

隱含地繫結失去繫結被退回到全域變數也就是他只是一個參考,或是在嚴格模式下的 undefined,就是隱含地失去。

function foo(){
    console.log(this.a);
}

var obj ={
    a: 2,
    foo: foo
};

var bar = obj.foo; // reference
var a = "Welcome to global";

bar(); "Welcome to global"

還記得剛剛說過"重要的是呼叫的地點",而 bar 被叫的地點其實很單純就是 global 。

接著當傳遞一個 callback 時會花森什麼事?

function foo(){
    console.log(this.a);
}

function bar(cb){
    cb();
}

var obj = {
    a: 3,
    foo: foo
};

var a = "Welcome to global";

bar(obj.foo); "Welcome to global"

wow~ wow~ wow~

參數的傳遞只是一個隱含的指定,所以想當然爾就會跟剛剛提的結果一樣。

另外還有一個常見的情況是當 callback 把 this 指向觸發該事件的 DOM 元素就是被刻意的更改 this 那也是一個蛋疼的情況。

...

好!

以上是今天的內容
明天接著介紹的是今天沒講完的"明確的繫結"
還有當有多個規則能夠套用時的優先順序。

敬請期待~


參考來源:

你所不知道的 JS|範疇與 Closures,this 與物件原型 (You Don't Know JS: this & Object Prototypes))


上一篇
【這些年我似是非懂的 Javascript】Day 21 - 是這個不是那個的 this # Part 1.
下一篇
【這些年我似是非懂的 Javascript】Day 23 - 是這個不是那個的 this # Part 3.
系列文
【這些年我似是非懂的 Javascript】34
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言