📓
Something About JavaScript
  • Introduction
  • Day 1:前言
  • Day 2:資料型態的夢魘——動態型別加弱型別(1)
  • Day 3:資料型態的夢魘——動態型別加弱型別(2)
  • Day 4:動態型別加弱型別不是罪——怎麼 JavaScript 一摔就變成個印度阿三?
  • Day 5:湯姆克魯斯與唐家霸王槍——變數的作用域(Scope) (1)
  • Day 6:湯姆克魯斯與唐家霸王槍——變數的作用域(Scope) (2)
  • Day 7:傳統 var 關鍵字的不足
  • Day 8:var 掰掰 —— ES6 更嚴謹安全的 let 和 const
  • Day 9:圖解變數作用域(Scope)
  • Day 10:程式也懂電梯向上? —— Hoisting
  • Day 11:Strict Mode (嚴謹模式)
  • Day 12:看 Strict Mode 如何施展「還我漂亮拳」(1)
  • Day 13:看 Strict Mode 如何施展「還我漂亮拳」(2)
  • Day 14:來挖挖恐龍骨 —— with 語法
  • Day 15:this 關鍵字 (1)
  • Day 16:this 關鍵字 (2)
  • Day 17:this 關鍵字 (3)
  • Day 18:this 關鍵字 (4)
  • Day 19:函數定義 (Function Definition) 的 100 種寫法
  • Day 20:ES6 的箭頭函數 (Arrow Functions)
  • Day 21:箭頭函數 (Arrow Functions) 的 this 和你想的不一樣 (1)
  • Day 22:箭頭函數 (Arrow Functions) 的 this 和你想的不一樣 (2)
  • Day 23:ES6 物件實字威力加強版 (Enhanced Object Literals)
  • Day 24:函數呼叫 (Function Invocation) 與立即函數 (Self-Invoking Functions)
  • Day 25:不是多了塊魚 —— 立即函數的應用整理
  • Day 26:程式界的哈姆雷特 —— Pass by value, or Pass by reference?
  • Day 27:別管變數 Pass by Whatever,尋找容易理解的銀色子彈 (Silver Bullet)
  • Day 28:閉包 (Closures)
  • Day 29:閉包 (Closures) 進階打怪實戰
  • Day 30:ES10 醞釀中 —— 擁抱 JS の 未來
Powered by GitBook
On this page
  • 函數執行環境下 (Function Context) (續)
  • 2. 簡易呼叫 (Simple Call)
  • 3. HTML 事件處理 (HTML Event Handlers)
  • 4. 顯性函數綁定之 bind() 篇 (Explicit Function Binding for bind())
  • References

Was this helpful?

Day 16:this 關鍵字 (2)

函數執行環境下 (Function Context) (續)

2. 簡易呼叫 (Simple Call)

this 物件:

  • 一般模式下:Global 物件。

  • 嚴謹模式下:undefined

簡易呼叫指的是函數被單獨呼叫,前面沒有帶任何呼叫物件的情境。

例如這樣的語法:

myFunc();

當函數被單獨呼叫,無論呼叫地點在全域環境還是函數環境內,此時執行這段程式的預設綁定擁有者是 Global 物件。

需要注意的是,這是指一般模式下的行為,一定會設定一個綁定物件,因為程式碼沒有指定呼叫物件,Global 物件就被推派出來當預設綁定者。

但基於安全性上的考量,嚴謹模式下不會作呼叫物件的強制給予,也就是說不會預設綁定 Global 物件當呼叫物件,程式碼沒指定就當沒有,因此 this 會是 undefined。

節錄 W3Schools 的原文:

  • When used alone, the owner is the Global object.

  • The Global object (the owner of the function) is the default binding.

  • Strict mode does not allow default binding.

根據函數被呼叫的地點不同,有幾種情境。

2.1. 全域環境 (Global Context) 下定義函數 & 呼叫函數

一般模式下,this 會綁定 Global 物件,在 HTML 環境裡就是 window 物件:

function f1(){
  return this;
}

console.log( f1() ); // `window`

在嚴格模式下,this 不會作預設綁定,會是 undefined:

"use strict";

function f1(){
  return this;
}

console.log( f1() ); // undefined

但其實對簡易呼叫來說,在哪裡被定義和呼叫都不重要,再看下一個例子會更明白。

2.2. 內部函數 (Inner Functions)

內部函數是指在 A 函數內定義一個 B 函數,然後在 A 函數裡呼叫 B。

例如以下例子 (一般模式):

var x = 10;
var obj = {
    x: 20,
    f: function(){
        console.log('Output 1: ', this.x);
        var foo = function(){ console.log('Output 2: ', this.x); }
        foo();
    }
};

obj.f();

執行結果:

Output 1:  20
Output 2:  10

這個例子是在 obj.f() 內再定義一個內部函數 foo() ,進行內部呼叫。

如前面所說,foo() 沒有指定呼叫物件,this 就是 Global 物件,因此 foo() 所印出的 this.x 值會是全域變數的 x,而非 obj 的 x (Output 2)。

如果這裡想讓 foo() 可以取到obj.x,可以使用一個變數去儲存執行 obj.f() 時的 this 物件。

var x = 10;
var obj = {
    x: 20,
    f: function(){
        console.log('Output 1: ', this.x);
        var me = this;   // Use a variable to store the `this` object
        var foo = function(){ console.log('Output 2: ', me.x); }  // Access `obj.x` via `me.x`  
        foo();
    }
};

obj.f();

執行結果:

Output 1:  20
Output 2:  20

3. HTML 事件處理 (HTML Event Handlers)

this 物件:接受該事件的 HTML 元素 (HTML Element)。

在 HTML 元件的事件 Callback 裡,this 就是該事件的 HTML 元素。

例如下面例子,onclick 裡的 this,指的就是 <button> 元素本身。

<button onclick="console.log(this); this.style.display='none';">
     Click to Remove Me!
</button>

4. 顯性函數綁定之 bind() 篇 (Explicit Function Binding for bind())

this 物件:新函數物件被指定的綁定物件,也就是 Function.prototype.bind() 的第一個參數。

ES5 導入了 Function.prototype.bind,可以為一個函數建立一個繼承該函數 prototype 的新函數物件,但綁定一個固定的擁有者。

換句話說,無論新的函數物件怎麼被呼叫,函數內的 this 都會是當初綁定的那個擁有者物件。

此外,透過 Function.prototype.bind 的綁定,一般模式或嚴謹模式是一樣的結果。

4.1. 一般模式下的範例

例如下面的例子:

var getFullName = function() {
    return this.firstName + " " + this.lastName;
}

var firstName = "One", lastName = "Jar";
var introIronMan = getFullName.bind( { firstName: "Tony", lastName : "Stark" } );
var introCaptainAmerica = getFullName.bind( { firstName: "Steven", lastName : "Rogers" } );

console.log(getFullName());           // "One Jar"
console.log(introIronMan());          // "Tony Stark"
console.log(introCaptainAmerica());   // "Steven Rogers"

上面例子在全域環境 (Global Context) 定義了函數 getFullName():

  • 透過簡單呼叫去執行 getFullName(),也是上面 2.1 節所舉的情境。

    • 在一般模式下會預設綁定 Global 物件作為 this 值。

    • 因此函數內會找到全域變數 firstName 和 lastName,因而印出 "One Jar"。

  • 使用 getFullName().bind(),分別產生了兩個新的函數物件,繼承了 getFullName() 的 prototype,但各自綁定了固定的擁有者物件。

    • introIronMan 函數物件綁定了擁有者物件 { firstName: "Tony", lastName : "Stark" } 。

    • introCaptainAmerica 函數物件綁定了擁有者物件 { firstName: "Steven", lastName : "Rogers" } 。

  • 一樣透過簡單呼叫的形式去呼叫 introIronMan() 和 introCaptainAmerica(),函數內的 this 值會是各自當初綁定的物件 (而非 Global 物件)。

4.2. 嚴謹模式下有同樣的行為

"use strict";

var getFullName = function() {
    return this.firstName + " " + this.lastName;
}

var firstName = "One", lastName = "Jar";
var introIronMan = getFullName.bind( { firstName: "Tony", lastName : "Stark" } );
var introCaptainAmerica = getFullName.bind( { firstName: "Steven", lastName : "Rogers" } );

console.log(getFullName());          // TypeError: Cannot read property 'firstName' of undefined
console.log(introIronMan());         // "Tony Stark"
console.log(introCaptainAmerica());  // "Steven Rogers"
  • 上面執行 getFullName() 時,因為是嚴謹模式,this 不再預設綁定 Global 物件,因此是 undefined (2.1 節情境)。

  • introIronMan() 和 introCaptainAmerica() 不受影響。

4.3. Binding 就像山盟海誓,只有第一次有效

需要注意的是,對一個函數物件來說,只有第一次的 Binding 動作有效。

透過 Function.prototype.bind 所建立的新函數物件 A,如果企圖用 Function.prototype.bind 再去建立一個新函數物件 B 並綁定新擁有者,因為函數物件 B 繼承了 A 的 prototype,包含當初的綁定者,因此無論是否給予新的綁定對象都沒有用。

但第二次綁定的當下並不會拋錯,只是沒有效果,即使在嚴謹模式下也不會 (感覺這也是嚴謹模式的遺珠)。

"use strict";

var getFullName = function() {
    return this.firstName + " " + this.lastName;
}

var introIronMan = getFullName.bind( { firstName: "Tony", lastName : "Stark" } );
var introClone = introIronMan.bind();
var introSpiderMan = introIronMan.bind( { firstName: "Peter", lastName : "Parker"} );

console.log(introClone());        // "Tony Stark"
console.log(introSpiderMan());    // "Tony Stark"

References

PreviousDay 15:this 關鍵字 (1)NextDay 17:this 關鍵字 (3)

Last updated 4 years ago

Was this helpful?

(Source: )

W3Schools - The JavaScript this Keyword
this - JavaScript | MDN
#Javascript:this用法整理 | 英特尔® 软件
JavaScript 語言核心(11)this 是什麼? by caterpillar | CodeData
網路圖片