進(jìn)擊的 JavaScript(六) 之 this

記得剛開始,我理解 this 的時(shí)候 也是云里霧里的,哈哈,希望通過(guò)這篇文章,對(duì)你有幫助吧。

關(guān)于 this 最多的說(shuō)法,就是:誰(shuí)調(diào)用它,this就指向誰(shuí)。這話呢,不能說(shuō)它錯(cuò)了,只能說(shuō)它講的不嚴(yán)謹(jǐn),為什么呢?我們先來(lái)了解下 this 的幾種綁定規(guī)則。

一、默認(rèn)綁定

默認(rèn)綁定 發(fā)生在全局環(huán)境 。

全局環(huán)境中,this 默認(rèn)綁定到 window。(嚴(yán)格模式下一樣)

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

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

//666


二、隱式綁定

隱式綁定 發(fā)生在 方法調(diào)用(執(zhí)行)。

什么是方法呢?通常把 對(duì)象的屬性值 是函數(shù)的,稱為方法。

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

//這里obj 對(duì)象里 的fun 屬性值是個(gè)函數(shù), 就把 這個(gè)fun 屬性稱為方法了。

通常,方法調(diào)用時(shí),this 隱式綁定到其 所屬的對(duì)象 上。

var a = "window";

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

obj.fun();

//"obj"

來(lái)個(gè)難一點(diǎn)的:

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

obj1.obj2.fun();

//"obj2"

這里的答案 跟你想的一樣嗎? 出現(xiàn)這個(gè)答案的關(guān)鍵 就是于,fun 函數(shù) 在作為對(duì)象方法執(zhí)行時(shí), this 綁定的是它的 所屬對(duì)象,也就是 obj2 。 而非外層 的 obj1。

三、隱式綁定丟失

在判斷是否是隱式綁定的時(shí)候,最容易出問(wèn)題的地方就是發(fā)生在 隱式綁定丟失。

隱式丟失是指被隱式綁定的函數(shù)丟失綁定對(duì)象,從而綁定到window。這種情況容易出錯(cuò)卻又常見。(嚴(yán)格模式下,綁定到undefined)

隱式綁定丟失 一般 發(fā)生在 函數(shù)獨(dú)立調(diào)用時(shí)。

啥是獨(dú)立調(diào)用呢?就是一個(gè)簡(jiǎn)單的函數(shù)執(zhí)行. 函數(shù)名的前面沒(méi)有任何引導(dǎo)內(nèi)容。

function ff(){};

ff();   //獨(dú)立調(diào)用

當(dāng)函數(shù)獨(dú)立調(diào)用(執(zhí)行)時(shí),this 就會(huì)隱式綁定丟失,而綁定到 window 對(duì)象上。(非嚴(yán)格模式下)

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

那么嚴(yán)格模式下呢?是指向 undefined 的。

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

//undefined

考考你:

var a = "window";

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

var fun2 = obj.fun;

fun2();
//"window"

判斷是否隱式綁定丟失的關(guān)鍵就在于, 判斷函數(shù) 是否是哪種調(diào)用。

上面的例子,關(guān)鍵點(diǎn)就在 最后兩行代碼。
先看其中的第一行:

var fun2 = obj.fun;

這里把 obj 的fun 方法 賦值給了 一個(gè)變量 fun2,這里的 fun 并沒(méi)有作為對(duì)象的方法來(lái)執(zhí)行,因?yàn)?,fun 方法這里沒(méi)有執(zhí)行。

其后:

fun2();

再執(zhí)行 fun2,它保存著 fun1 方法,這時(shí)候執(zhí)行 fun2(等于fun1) ,但是,它是獨(dú)立調(diào)用。因?yàn)?,沒(méi)有作為對(duì)象的方法來(lái)調(diào)用。所以 this 就被指向 window了。

那么怎么解決隱式丟失問(wèn)題呢?

var a = "window";

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

obj.fun()();

//"window"

//這里我們想要的是 obj里 a 的值,可是,隱式綁定丟失導(dǎo)致獲取到了 window 里 a 的值。

可以基礎(chǔ)好的已經(jīng)知道答案了:

var a = "window";

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

obj.fun()();

//"obj"

因?yàn)?fun 是作為方法調(diào)用的,所以 this 綁定到 obj 對(duì)象上,因此,我們就可以先用一個(gè)變量 that 來(lái)保存 this,然后 在內(nèi)部的 匿名函數(shù)中 使用 that 就可以了。它保存著 上面 this 的綁定對(duì)象。

忽然靈機(jī)一動(dòng),想出個(gè)題目,看人家都玩出題,我也試試,哈哈:

var a = "window";

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

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

fun()

//“你猜”

這道題中 有立即執(zhí)行函數(shù)、this問(wèn)題,哈哈,乍一看挺惡心,其實(shí)看完上面的,應(yīng)該可以看出來(lái)的。

四、顯示綁定

通過(guò)call()、apply()、bind()方法把 this 綁定到對(duì)象上,叫做顯式綁定。對(duì)于被調(diào)用的函數(shù)來(lái)說(shuō),叫做間接調(diào)用。

var a = "window"

var obj = {
    a:"obj",
}

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

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

這里使用了 call 方法,把fun 中的 this 綁定到 obj 對(duì)象上。

javascript內(nèi)置的一些函數(shù),具有顯式綁定的功能,如數(shù)組的5個(gè)迭代方法:map()、forEach()、filter()、some()、every(),以及創(chuàng)建對(duì)象的 Object.create() 函數(shù)(后面原型鏈中會(huì)細(xì)說(shuō)),都可以手動(dòng)綁定this。

大家可以去看下API文檔,數(shù)組的這幾個(gè)函數(shù)的最后一個(gè)參數(shù),就是指定函數(shù)內(nèi) this 的綁定,如果不指定,則是window,嚴(yán)格模式下是undefined。

var a = [1,2,3];

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

//綁定 this  為 a 這個(gè)數(shù)組

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

五、new 綁定

如果 使用 new 來(lái)創(chuàng)建對(duì)象,因?yàn)?后面跟著的是構(gòu)造函數(shù),所以稱它為構(gòu)造器調(diào)用。對(duì)于this綁定來(lái)說(shuō),稱為new綁定。

想知道 構(gòu)造器調(diào)用 中 this 的綁定,就要知道 new 到底做了啥了。

先來(lái)個(gè) new 的實(shí)現(xiàn)。看不懂不要緊,在后面原型鏈那篇,還會(huì)說(shuō)的。

function New(proto){  //proto 為傳進(jìn)來(lái)的構(gòu)造函數(shù)
    var obj = {};
    obj.__proto__ = proto.prototype;

    proto.apply(obj, Array.prototype.slice.call(argument,1));
    //你這要看懂這步就行。這里把構(gòu)造函數(shù)里的 this  綁定到了 新的obj 對(duì)象上,最后 返回了該新對(duì)象,作為實(shí)例對(duì)象。

    return obj;
}

所以在使用 new 來(lái)創(chuàng)建實(shí)例對(duì)象時(shí),new 內(nèi)部把 構(gòu)造函數(shù)的 this 綁定到 返回的新對(duì)象 上了。

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

總結(jié): this的四種綁定規(guī)則:隱式綁定、隱式綁定丟失、顯式綁定和new綁定,分別對(duì)應(yīng)函數(shù)的四種調(diào)用方式:方法調(diào)用、獨(dú)立調(diào)用、間接調(diào)用和構(gòu)造器調(diào)用。


附錄:

1、關(guān)于this綁定 的優(yōu)先級(jí)問(wèn)題。

簡(jiǎn)單提一下吧:

new 綁定 > 顯示綁定 > 隱式綁定 > 默認(rèn)綁定 。

2、ES6 中,箭頭函數(shù)的 this 綁定。

箭頭函數(shù)內(nèi)的 this 綁定的 是所屬的環(huán)境(函數(shù)或者對(duì)象), 它是固定不變的。

先看下上面的這個(gè)例子

var a = "window";

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

obj.fun()();

//"window"

上面我們使用 一個(gè)變量來(lái)保存 this 的綁定,下面我們來(lái)用 箭頭函數(shù)解決問(wèn)題

var a = "window";

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

obj.fun()();

//"obj"

實(shí)際上,箭頭函數(shù)內(nèi)部是沒(méi)有this 的,所以,它不能使用 new 構(gòu)造器調(diào)用,call顯示綁定。所以它內(nèi)部就是使用了一個(gè)變量來(lái)保存 箭頭函數(shù) 所屬環(huán)境的(函數(shù)或者對(duì)象) this。

就相當(dāng)于:

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()();
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本文主要內(nèi)容參考此文章,主要是為了記錄 產(chǎn)品需求 用戶從qq/微信分享出去的H5頁(yè)面,當(dāng)點(diǎn)擊H5頁(yè)面的某個(gè)按鈕時(shí),...
    _CLAY_閱讀 10,067評(píng)論 0 2
  • 書,是人類最好的朋友,也是我們一生中不可缺少的一部分。書是人類的好老師,讓我們從中獲得很多知識(shí)。書還能在我...
    小羽_235c閱讀 172評(píng)論 0 0
  • 安卓開發(fā)過(guò)程中難免會(huì)碰到需要選擇日期時(shí)間的情況,由于大部分android初級(jí)教程都沒(méi)教怎么選擇時(shí)間,初學(xué)者碰到這種...
    籬開羅閱讀 11,768評(píng)論 4 44
  • 孩子是一個(gè)獨(dú)立的個(gè)體,TA從脫離母體的那一刻,就是一個(gè)獨(dú)立的人。但是很多父母認(rèn)為孩子小,總喜歡替孩子定目標(biāo),拿主意...
    蘋果Apple來(lái)了閱讀 298評(píng)論 0 1

友情鏈接更多精彩內(nèi)容