進擊的 JavaScript(六) 之 this

記得剛開始,我理解 this 的時候 也是雲裏霧裏的,哈哈,但願經過這篇文章,對你有幫助吧。javascript

關於 this 最多的說法,就是:誰調用它,this就指向誰。這話呢,不能說它錯了,只能說它講的不嚴謹,爲何呢?咱們先來了解下 this 的幾種綁定規則。java

1、默認綁定

默認綁定 發生在全局環境 。數組

全局環境中,this 默認綁定到 window。(嚴格模式下同樣)app

console.log(this === window);
//true

"use strict";    //使用嚴格模式執行代碼
var a = 666;
console.log(this.a)

//666


2、隱式綁定

隱式綁定 發生在 方法調用(執行)。函數

什麼是方法呢?一般把 對象的屬性值 是函數的,稱爲方法。this

var obj = {
    fun: function(){}
}

//這裏obj 對象裏 的fun 屬性值是個函數, 就把 這個fun 屬性稱爲方法了。

一般,方法調用時,this 隱式綁定到其 所屬的對象 上。prototype

var a = "window";

var obj = {
    a: "obj",
    
    fun: function(){
        console.log(this.a);
    }
}

obj.fun();

//"obj"

來個難一點的:code

var obj1 = {
    a: "obj1",
   
    obj2: {
        a: "obj2",
        fun: function(){
            console.log(this.a);
        }
    }
}

obj1.obj2.fun();

//"obj2"

這裏的答案 跟你想的同樣嗎? 出現這個答案的關鍵 就是於,fun 函數 在做爲對象方法執行時, this 綁定的是它的 所屬對象,也就是 obj2 。 而非外層 的 obj1對象

3、隱式綁定丟失

在判斷是不是隱式綁定的時候,最容易出問題的地方就是發生在 隱式綁定丟失。ip

隱式丟失是指被隱式綁定的函數丟失綁定對象,從而綁定到window。這種狀況容易出錯卻又常見。(嚴格模式下,綁定到undefined)

隱式綁定丟失 通常 發生在 函數獨立調用時。

啥是獨立調用呢?就是一個簡單的函數執行. 函數名的前面沒有任何引導內容。

function ff(){};

ff();   //獨立調用

當函數獨立調用(執行)時,this 就會隱式綁定丟失,而綁定到 window 對象上。(非嚴格模式下)

function fun(){
    console.log(this === window);
}
fun();
//true

那麼嚴格模式下呢?是指向 undefined 的。

function fun(){
    "use strict";    //使用嚴格模式執行代碼
    console.log(this);
}
fun();

//undefined

考考你:

var a = "window";

var obj = {
    a: "obj",
    
    fun1: function(){
        console.log(this.a);
    }
}

var fun2 = obj.fun;

fun2();
//"window"

判斷是否隱式綁定丟失的關鍵就在於, 判斷函數 是不是哪一種調用。

上面的例子,關鍵點就在 最後兩行代碼。
先看其中的第一行:

var fun2 = obj.fun;

這裏把 obj 的fun 方法 賦值給了 一個變量 fun2,這裏的 fun 並無做爲對象的方法來執行,由於,fun 方法這裏沒有執行。

其後:

fun2();

再執行 fun2,它保存着 fun1 方法,這時候執行 fun2(等於fun1) ,可是,它是獨立調用。由於,沒有做爲對象的方法來調用。因此 this 就被指向 window了。

那麼怎麼解決隱式丟失問題呢?

var a = "window";

var obj = {
    a: "obj",
    
    fun: function(){
        return function(){
            console.log(this.a);
        }
    }
}

obj.fun()();

//"window"

//這裏咱們想要的是 obj裏 a 的值,但是,隱式綁定丟失致使獲取到了 window 裏 a 的值。

能夠基礎好的已經知道答案了:

var a = "window";

var obj = {
    a: "obj",
    
    fun: function(){
        var that = this;
        return function(){
            console.log(that.a);
        }
    }
}

obj.fun()();

//"obj"

由於 fun 是做爲方法調用的,因此 this 綁定到 obj 對象上,所以,咱們就能夠先用一個變量 that 來保存 this,而後 在內部的 匿名函數中 使用 that 就能夠了。它保存着 上面 this 的綁定對象。

突然靈機一動,想出個題目,看人家都玩出題,我也試試,哈哈:

var a = "window";

function fun(){
    var a = "fun";

    return (function(){
        return this.a;
    })()
}

fun()

//「你猜」

這道題中 有當即執行函數、this問題,哈哈,乍一看挺噁心,其實看完上面的,應該能夠看出來的。

4、顯示綁定

經過call()、apply()、bind()方法把 this 綁定到對象上,叫作顯式綁定。對於被調用的函數來講,叫作間接調用

var a = "window"

var obj = {
    a:"obj",
}

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

fun.call(obj);
//"obj";

這裏使用了 call 方法,把fun 中的 this 綁定到 obj 對象上。

javascript內置的一些函數,具備顯式綁定的功能,如數組的5個迭代方法:map()、forEach()、filter()、some()、every(),以及建立對象的 Object.create() 函數(後面原型鏈中會細說),均可以手動綁定this。

你們能夠去看下API文檔,數組的這幾個函數的最後一個參數,就是指定函數內 this 的綁定,若是不指定,則是window,嚴格模式下是undefined

var a = [1,2,3];

a.forEach(function(){
    console.log(this)
},a);

//綁定 this  爲 a 這個數組

//(3) [1, 2, 3]
//(3) [1, 2, 3]
//(3) [1, 2, 3]

5、new 綁定

若是 使用 new 來建立對象,由於 後面跟着的是構造函數,因此稱它爲構造器調用。對於this綁定來講,稱爲new綁定。

想知道 構造器調用 中 this 的綁定,就要知道 new 到底作了啥了。

先來個 new 的實現。看不懂沒關係,在後面原型鏈那篇,還會說的。

function New(proto){  //proto 爲傳進來的構造函數
    var obj = {};
    obj.__proto__ = proto.prototype;

    proto.apply(obj, Array.prototype.slice.call(argument,1));
    //你這要看懂這步就行。這裏把構造函數裏的 this  綁定到了 新的obj 對象上,最後 返回了該新對象,做爲實例對象。

    return obj;
}

因此在使用 new 來建立實例對象時,new 內部把 構造函數的 this 綁定到 返回的新對象 上了。

function Person(name){
    this.name = name;
}
var c = new Person("zdx");
c.name;

總結: this的四種綁定規則:隱式綁定、隱式綁定丟失、顯式綁定和new綁定,分別對應函數的四種調用方式:方法調用、獨立調用、間接調用和構造器調用。


附錄:

一、關於this綁定 的優先級問題。

簡單提一下吧:

new 綁定 > 顯示綁定 > 隱式綁定 > 默認綁定

二、ES6 中,箭頭函數的 this 綁定。

箭頭函數內的 this 綁定的 是所屬的環境(函數或者對象), 它是固定不變的。

先看下上面的這個例子

var a = "window";

var obj = {
    a: "obj",
    
    fun: function(){
        return function(){
            console.log(this.a);
        }
    }
}

obj.fun()();

//"window"

上面咱們使用 一個變量來保存 this 的綁定,下面咱們來用 箭頭函數解決問題

var a = "window";

var obj = {
    a: "obj",
    
    fun: function(){
        return () => {
            console.log(this.a);
        }
    }
}

obj.fun()();

//"obj"

實際上,箭頭函數內部是沒有this 的,因此,它不能使用 new 構造器調用,call顯示綁定。因此它內部就是使用了一個變量來保存 箭頭函數 所屬環境的(函數或者對象) this

就至關於:

var a = "window";

var obj = {
    a: "obj",
    
    fun: function(){
            that = this;
            return function(){
                console.log(that.a);
            }
    }
}

obj.fun()();

//"obj"

考考你:

var a = "window";

var obj = {
    a: "obj",
    
    fun1: function(){
        return () => {
            console.log(this.a);
        }
    }
}

var fun2  = obj.fun1;

fun2()();
相關文章
相關標籤/搜索