iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 3
0
自我挑戰組

玩轉 React 從0到1系列 第 8

【Day 8】關於ES6 關鍵字 this

  • 分享至 

  • xImage
  •  

前言

對於寫 JS 的朋友,我想這主題算是 最熟悉的陌生人,對於新手來說這是必懂的主題,對於資深的人來說可能在這上面踩過不少雷,但你真的懂嗎 ? 到底什麼是 this ?

定義上:
this 這個關鍵字代表的值為目前執行環境的 ThisBinding
在大多數情況下,this 會因為 function 呼叫的方式而有所不同

So, this 到底是什麼? 看著定義我沈默 3 秒,最好看的懂拉 ....
在開始說 this 前,我們先說說 Context(上下文):

Context(上下文)

Context 指的是函式在被呼叫執行時,所處的物件環境。

Context 決定了 JS 執行過程中可以獲取哪些變量、數據、函數,每一個 Context 都會綁定一個變量對象(Variable Object),它用來儲存 Context 所有已經定義的變量,函數。

Context vs Scope(作用域):
Scope 指的是在函式中變數的可使用範圍,在函式定義的時候就已經決定了。

所以 this 表示的其實是 函數調用的上下文 (context) ,而 context 默認是全局 window。

ES6 以前 this

默認綁定 全局

console.log(this);   // this 等於 ECMAScript 在瀏覽器環境的 global對象,window

function bar() {
    'use strict'
    console.log(this);
}
bar()  // undefined

默認綁定作用於函數直接調用,此時 this 會指向全局 window,但嚴格模式會指向 undefined

顯示綁定 (call, apply, bind)

function getName() {
    console.log(this.name);
}
var meggie = {
    name: 'Meggie';
}
var jacky = {
    name: 'Jacky';
}
getName.apply(meggie); //'Meggie'
getName.apply(jacky); // 'Jacky'

顯示綁定的優點?
可以明確的指定要執行 function 中的 this 是什麼,不需要透過另一個變數來暫存 this 的方式來獲取,這方法也往往更直觀,不像 callback function 會改變指向。

其實 隱式綁定都只是語法糖,都可以寫成 apply,bind,call 的方式,apply,bind,call 雖然麻煩但往往更正規。

Call vs Apply vs Bind:

  • Call == Appply,只是傳入參數不同而已:
    function.call (thisArg, arg1, arg2, ...)
    function.apply (thisArg, [argsArray])

都是將 this 以及 parameters 傳入,重新定義 this 指向,而且會立刻執行前面的 function

  • Bind:
    func.bind (thisArg[, arg1[, arg2[, ...]]])

是借用舊有的函數來建立一個新的函數,並且將 this 綁定到物件中,不會立刻執行前面的 function
Bind 函數存在著多次綁定的問題,如果多次綁定this,則以第一次為主

隱式綁定 函數功能 (function)

var obj = {
    id: 10,
    getId: function() {
        console.log(this.id);
    }
}
obj.getId() // this 為 object

隱式綁定作用於函數,首先查看是不是有Context 的對象,如果有那麼this會綁定到這個對象上。

隱式綁定丟失 this 的問題:

const obj = {
  foo: function() {
    console.log(this);
  }
}

obj.foo();  // obj
setTimeout(obj.foo, 0);  // window
// 解決辦法:setTimeout(obj.foo.bind(obj), 0) // obj
setTimeout(function() {
  obj.foo();  // obj
},10);

為什麼作為 obj.foo() 的時候就沒問題,而 callback this卻丟失了呢? 因為 obj.foo 本身屬於匿名函數,這其實是一個函數上直接的調用,所以應用了 默認綁定,導致 this 丟失。

const obj = {
  a: function () {
    console.log(this) // obj
    function a1() {
      console.log(this) // window
    }
    // 解決辦法,改用箭頭函數 var a1 = () => { console.log(this); }
    a1()
  }
}
obj.a()

所以來考考大家,為什麼執行 a1() 的時候返回的是 window 的 this 呢?
因為這邊的 a1() 也是屬於函數直接調用,所以為 window

構造函數 (constructor物件產生時會被呼叫)

function User() {}
User.prototype.getId = function() {
    console.log(this.id);
}
var user = new User();
user.id = 10;
user.getId() // 10,因為 this 指向 User

new在創建實例(instance)的時候事實上是對新實例 this 不斷地賦值,將 __proto__ 指向原型。

ES6 的 this (添加)

箭頭函數

  • 箭頭函數沒有自己的 this 值,它繼承外面作用域的 this

以下這個例子,因為 ES6 是嚴格模式,嚴格模式下的全域作用域為 undefind,所以 this 為 undefined:

const foo = (options) => {
  console.log(this); // undefined
};

結論

  • 介紹了 ES6 中的 this
  • 介紹了 Call, Apply, Bind 方法
    /images/emoticon/emoticon01.gif

參考

this 的值到底是什么?一次说清楚
JS 紀錄7 - this 指向判斷的方式
this綁定的四種方法


上一篇
【Day 7】關於ES6 模組系統
下一篇
【Day 9】關於ES6 的 同步與異步
系列文
玩轉 React 從0到130
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言