成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

全面解析JS中的this

calx / 3338人閱讀

摘要:當(dāng)我們不想再對(duì)象內(nèi)部間接包含引用函數(shù),而像在某個(gè)對(duì)象上強(qiáng)制調(diào)用函數(shù)。我們可以用中內(nèi)置的和的方法來(lái)實(shí)現(xiàn),這兩個(gè)方法的第一個(gè)參數(shù)是一個(gè)對(duì)象,是給準(zhǔn)備的,接著再調(diào)用函數(shù)時(shí)將其綁定到。

this是什么

在javascript中,每個(gè)執(zhí)行上下文可以抽象成一組對(duì)象

this是與執(zhí)行上下文相關(guān)的特殊對(duì)象,任何對(duì)象都可以用作this上下文的值,一個(gè)重要的注意事項(xiàng)就是this值是執(zhí)行上下文的屬性,但不是變量對(duì)象的屬性。這樣的話,與變量相反,this值不會(huì)參與標(biāo)識(shí)符解析,即在訪問(wèn)代碼時(shí),他的值直接來(lái)自執(zhí)行上下文,也沒(méi)有任何作用域鏈查找,在進(jìn)入上下文中,this只能確定一次。所以this的值是和其所處的上下文環(huán)境有關(guān)系。

this全面解析
1.調(diào)用位置

在歷屆this的綁定之前,首先要理解調(diào)用位置,調(diào)用位置就是函數(shù)在代碼中內(nèi)調(diào)用的位置(而不是聲明的位置),例子:

function baz(){
    // 當(dāng)前調(diào)用棧是: baz
    // 因此,當(dāng)前調(diào)用位置是全局作用域
    console.log("baz");
    bar(); // <-- bar的調(diào)用位置
}

function bar(){
    // 當(dāng)前調(diào)用棧是baz -> bar
    // 因此調(diào)用位置在baz中
    console.log("bar");
    foo();// <-foo的調(diào)用位置
}
function foo(){
    // 當(dāng)前調(diào)用棧是baz -> bar -> foo
    // 調(diào)用位置在bar中
    
    console.log("foo");
}
baz() // <- baz的調(diào)用位置
2. 綁定規(guī)則
2.1 默認(rèn)綁定

首先要介紹的最常見(jiàn)的函數(shù)調(diào)用類(lèi)型:獨(dú)立函數(shù)調(diào)用??梢园堰@條規(guī)則看作是無(wú)法應(yīng)用其他規(guī)則時(shí)的默認(rèn)規(guī)則

function foo(){
    console.log(this.a);
}
var a = 2;
foo(); //2

因?yàn)?b>foo()在全局執(zhí)行上下文中調(diào)用,所以this指向全局變量
如果使用嚴(yán)格模式,則不能將全局對(duì)象用于默認(rèn)綁定,因此this會(huì)綁定到undefined:

function foo(){
    "use strict"
    console.log(this.a);
}
var a = 2;
foo(); //error

雖然this的綁定規(guī)則完全取決于調(diào)用位置,但是只有foo()運(yùn)行在非嚴(yán)格模式下時(shí)。默認(rèn)綁定才能綁定到全局對(duì)象;在嚴(yán)格模式下調(diào)用foo()則不影響默認(rèn)綁定

function foo(){
    console.log(this.a);
}
var a = 2;
(function(){
    foo(); //2
})()
2.2 隱式綁定
function foo(){
    console.log(this.a);
}

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

obj.foo();

當(dāng)函數(shù)引用有上下文對(duì)象時(shí),隱式綁定規(guī)則會(huì)把函數(shù)調(diào)用中的this綁定到這個(gè)上下文對(duì)象,因?yàn)檎{(diào)用foo()時(shí)this被綁定到obj,因此this.aobj.a是一樣的
對(duì)象屬性引用鏈中只有上一層或者說(shuō)最后一層在調(diào)用位置起作用

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

var obj2 = {
    a: 42,
    foo: foo
}

var obj1 = {
    a: 2,
    obj2: obj2
}

obj1.obj2.foo(); //42
2.3 隱式丟失

被隱式綁定的函數(shù)會(huì)丟失綁定對(duì)象,也就是說(shuō)他會(huì)應(yīng)用默認(rèn)綁定,從而把this綁定到全局對(duì)象或者undefined

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

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

var bar = obj.foo; //函數(shù)別名
var a = "oops, global"; //a是全局對(duì)象的屬性。
bar(); //"oops, global"

雖然bar引用了obj.foo這個(gè)引用,但實(shí)際上他引用的是foo函數(shù)的本身。也就是說(shuō)bar()是一個(gè)在全局上下文中調(diào)用的函數(shù),因此this指向了全局對(duì)象。
這種情形頁(yè)出現(xiàn)在參數(shù)傳遞中。

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

function doFoo(fn){
    fn();
}

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

var a = "oops, global"; //a是全局對(duì)象的屬性
doFoo(obj.foo);

參數(shù)傳遞其實(shí)就是一種隱式賦值,因此我們傳入函數(shù)也會(huì)被隱式賦值。

2.4 顯示綁定

在分析隱式綁定時(shí),我們必須在一個(gè)對(duì)象內(nèi)部包含一個(gè)指向函數(shù)的屬性,并通過(guò)這個(gè)屬性間接引用函數(shù),從而把this間接(隱式)綁定到這個(gè)都對(duì)象上。
當(dāng)我們不想再對(duì)象內(nèi)部間接包含引用函數(shù),而像在某個(gè)對(duì)象上強(qiáng)制調(diào)用函數(shù)。我們可以用javascript中內(nèi)置的applycall的方法來(lái)實(shí)現(xiàn),這兩個(gè)方法的第一個(gè)參數(shù)是一個(gè)對(duì)象,是給this準(zhǔn)備的,接著再調(diào)用函數(shù)時(shí)將其綁定到this。因?yàn)槟憧梢灾苯又付?b>this的綁定對(duì)象,因此我們稱(chēng)之為顯式綁定。

function foo(){
    console.log(this.a);
}
var obj = {
    a: 2
}
foo.call(obj);  //2

通過(guò)foo.call(...)我們可以在調(diào)用foo時(shí)強(qiáng)制把他的this綁定到obj上。如果你傳入一個(gè)原始值(字符串類(lèi)型,布爾類(lèi)型或者數(shù)字類(lèi)型)來(lái)當(dāng)作this的綁定對(duì)象,這個(gè)原始值會(huì)被轉(zhuǎn)換成他的對(duì)象形式,也就是“裝箱”
我們通過(guò)顯示綁定的變種解決綁定丟失的問(wèn)題

function foo(){
    console.log(this.a);
}
var obj = {
    a: 2
}
var bar = function(){
    foo.call(obj);
};

bar(); //2
setTimeout(bar, 100); //2
//硬綁定的bar不可能在修改他的this
bar.call(window); //2

硬綁定的典型應(yīng)用場(chǎng)景就是創(chuàng)建一個(gè)包裹函數(shù),負(fù)責(zé)接收參數(shù)并返回值

function foo(something){
    console.log(this.a, something);
    return this.a + something;
}

var obj = {
    a: 2
}

var bar = function(){
    return foo.apply(obj, arguments);
} 
var b = bar(3); //2. 3
console.log(b); //5

另一種方式則是創(chuàng)建一個(gè)可以重復(fù)使用的輔助函數(shù)

function foo(something){
    console.log(this.a, something);
    return this.a + something;
}

var obj = {
    a: 2
}

function bind(fn, obj){
    return function(){
        return fn.apply(obj, arguments);
    }
}

var bar = bind(foo, obj);
var b = bar(3); //2 3
console.log(b); //5
2.5 apply,call,bind

之前介紹了applycall可以改變this的指向,現(xiàn)在來(lái)講講他們的區(qū)別以及ES5新增的方法bind
applycall之間最主要的區(qū)別在于傳入?yún)⑿问降牟煌?。他倆的第一個(gè)參數(shù)都是指定了函數(shù)體內(nèi)的this指向。
而第二個(gè)參數(shù)apply傳入為一個(gè)帶下標(biāo)的集合,這個(gè)集可以為數(shù)組,也可以為類(lèi)數(shù)組。apply方法把這個(gè)集合中的元素作為參數(shù)傳遞給被調(diào)用的函數(shù)

var func = function(a,b,c){
    alert([a, b, c]);  //1 2 3
}
func.apply(null, [1, 2, 3])

call傳入的參數(shù)數(shù)量不固定,跟apply相同的是,第一個(gè)參數(shù)也是函數(shù)體內(nèi)的this指向,從第二個(gè)參數(shù)開(kāi)始往后,每個(gè)參數(shù)依次傳入函數(shù)。

var func = function(a, b, c){
    alert([a, b, c]); //1 2 3
}
func.call(null, 1, 2, 3);

當(dāng)使用call或者apply的時(shí)候,如果我們傳入的第一個(gè)參數(shù)為null,函數(shù)體內(nèi)的this會(huì)指向默認(rèn)的宿主對(duì)象,在瀏覽器是window
大多數(shù)的高級(jí)瀏覽器已經(jīng)實(shí)現(xiàn)了bind方法用來(lái)指定函數(shù)內(nèi)部的this的指向

function foo(){
    console.log(this.a);
}
var obj = {
    a: 2
}

var bar = foo。bind(obj);

bar(); //2

bind(..)會(huì)返回一個(gè)硬編碼的新函數(shù),他會(huì)把你指定的參數(shù)設(shè)置為this的上下文并調(diào)用原始函數(shù)
我們也可以用apply模仿一個(gè)bind

Function.prototype.bind = function(){
    var self = this;
    var context = Array.prototype.shift().call(arguments);
    var args = Array.prototype.slice().call(arguments);
    return function(){
        this.apply(context, Array.prototype.concat.call(args, Array.prototype.shift().call(arguments);))
    }
}
var obj = {
    name: "foo"
};

var func = function(a, b, c, d){
    console.log(this.name);
    console.log([a, b, c, d]) //
}.bind(obj, 1, 2);

func(3,4);
2.6 new綁定

在javascript中,構(gòu)造函數(shù)只是一些使用new操作符時(shí)調(diào)用的函數(shù),它們并不會(huì)屬于某個(gè)類(lèi),也不會(huì)是實(shí)例化一個(gè)類(lèi)。
使用new來(lái)調(diào)用函數(shù),或者說(shuō)發(fā)生構(gòu)函數(shù)調(diào)用時(shí),會(huì)自動(dòng)執(zhí)行下面的操作
1.創(chuàng)建(或者說(shuō)構(gòu)造)一個(gè)去全新的對(duì)象。
2.這個(gè)新對(duì)象會(huì)被執(zhí)行[[prototype]]連接
3.這個(gè)新對(duì)象會(huì)綁定到函數(shù)調(diào)用的this
4.如果函數(shù)沒(méi)有其他返回對(duì)象,那么new表達(dá)式中的函數(shù)調(diào)用會(huì)自動(dòng)返回這個(gè)新對(duì)象。

function foo(a){
    this.a = a;
}
var bar = new foo(2);
console.log(bar.a); //2
軟綁定

前面我們說(shuō)過(guò)硬綁定這種方式綁定之后無(wú)法修改this值,會(huì)降低函數(shù)靈活性。
如果可以給默認(rèn)綁定指定一個(gè)全局對(duì)象和undefined以外的值,那就可以實(shí)現(xiàn)和硬綁定相同過(guò)的效果,同hi是保留隱式綁定或者顯示綁定修改this的能力

 Function.prototype.softbind = function(){
     var self = this;
     var context = [].shift.call(arguments);
     var args = [].slice.call(arguments);
     var bound = function(){
     return self.apply((!this|| this === (window || global))?obj:this, [].concat.call(args, [].slice.call(arguments)));
     }
     bound.prototype =Object.create(self);
     return bound;
}
    function foo(){
        console.log(this.name);
    }
    var obj = {
        name: "obj"
    }
    var obj1 = {
        name: "obj1"
    }
    var fooobj = foo.softbind(obj, 1);
    fooobj();  //name: obj
    obj1.foo = foo.softbind(obj);
    obj1.foo();    //name: obj1
    setTimeout(obj1.foo, 10); //name: obj

可以看到,軟綁定版本的foo()可以手動(dòng)講this綁定到obj1上,但如果應(yīng)用默認(rèn)綁定,則會(huì)將this綁定到obj上

this 語(yǔ)法

ES6中出現(xiàn)了不同與以上四種規(guī)則的特殊函數(shù)類(lèi)型: 箭頭函數(shù)。它是根據(jù)外層(外層或者全局)作用域來(lái)決定的

function foo(){
    return (a) => {
        //this 繼承來(lái)自foo()
        console.log(this.a)
    };
}
var obj1 = {
    a: 2
}

var obj2 = {
    a: 3
}
var bar = foo.call(obj1);
bar.call(obj2); //2 不是3!

foo()內(nèi)部創(chuàng)建的箭頭函數(shù)會(huì)捕獲調(diào)用時(shí)foo()this,由于foo()this綁定到obj1,barthis也會(huì)綁定到obj1,箭頭函數(shù)的綁定無(wú)法被更改。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/84996.html

相關(guān)文章

  • 【進(jìn)階3-1期】JavaScript深入之史上最全--5種this綁定全面解析

    摘要:在嚴(yán)格模式下調(diào)用函數(shù)則不影響默認(rèn)綁定。回調(diào)函數(shù)丟失綁定是非常常見(jiàn)的。因?yàn)橹苯又付ǖ慕壎▽?duì)象,稱(chēng)之為顯示綁定。調(diào)用時(shí)強(qiáng)制把的綁定到上顯示綁定無(wú)法解決丟失綁定問(wèn)題。 (關(guān)注福利,關(guān)注本公眾號(hào)回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo)) 本周正式開(kāi)始前端進(jìn)階的第三期,本周的主題是this全面解析,今天是第9天。 本計(jì)劃一共28期,每期重點(diǎn)攻克一個(gè)面試重...

    xavier 評(píng)論0 收藏0
  • this全面解析(二)

    摘要:在傳統(tǒng)的面向類(lèi)的語(yǔ)言中,構(gòu)造函數(shù)是類(lèi)中的一些特殊方法,使用初始化類(lèi)是會(huì)調(diào)用類(lèi)中的構(gòu)造函數(shù)。 在上一節(jié)中我們?cè)敿?xì)介紹了this的兩種綁定方式,默認(rèn)綁定和隱式綁定,在這一節(jié)我們繼續(xù)介紹this的另外兩種綁定方式顯示綁定和new綁定。那么,我們要解決的問(wèn)題當(dāng)然就是上一節(jié)中我們提到的:this丟失! 顯式綁定 在隱式綁定中,我們必須在一個(gè)對(duì)象的內(nèi)部包含一個(gè)指向函數(shù)的屬性,并通過(guò)這個(gè)屬性間接引用...

    iflove 評(píng)論0 收藏0
  • 【進(jìn)階1-1期】理解JavaScript 中的執(zhí)行上下文和執(zhí)行棧

    摘要:首次運(yùn)行代碼時(shí),會(huì)創(chuàng)建一個(gè)全局執(zhí)行上下文并到當(dāng)前的執(zhí)行棧中。執(zhí)行上下文的創(chuàng)建執(zhí)行上下文分兩個(gè)階段創(chuàng)建創(chuàng)建階段執(zhí)行階段創(chuàng)建階段確定的值,也被稱(chēng)為。 (關(guān)注福利,關(guān)注本公眾號(hào)回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo)) 本周正式開(kāi)始前端進(jìn)階的第一期,本周的主題是調(diào)用堆棧,,今天是第一天 本計(jì)劃一共28期,每期重點(diǎn)攻克一個(gè)面試重難點(diǎn),如果你還不了解本進(jìn)...

    import. 評(píng)論0 收藏0
  • 全面解析this

    摘要:在嚴(yán)格模式下,對(duì)象的函數(shù)中的指向調(diào)用函數(shù)的對(duì)象實(shí)例顯式綁定,,通過(guò)可以把的綁定到上。間接引用最容易在賦值時(shí)發(fā)生返回目標(biāo)函數(shù)的引用詞法之前介紹的種綁定規(guī)則可以包含所有正常的函數(shù),但是中介紹了一種無(wú)法使用這些規(guī)則的特殊函數(shù)類(lèi)型箭頭函數(shù)。 this到底指向什么? this關(guān)鍵詞是javaScript中最復(fù)雜的機(jī)制之一,一般有兩個(gè)誤區(qū):1.this指向函數(shù)自身;2.this指向函數(shù)的作用域; ...

    Y3G 評(píng)論0 收藏0
  • this全面解析(一)

    摘要:調(diào)用棧就是為了到達(dá)當(dāng)前執(zhí)行位置所調(diào)用的所有函數(shù)。由于無(wú)法控制回調(diào)函數(shù)的執(zhí)行方式,因此就沒(méi)有辦法控制調(diào)用位置得到期望的綁定,下一節(jié)我們會(huì)介紹如何通過(guò)固定來(lái)修復(fù)這個(gè)問(wèn)題。 在《你不知道的this》中我們排除了對(duì)于this的錯(cuò)誤理解,并且明白了每個(gè)函數(shù)的this是在調(diào)用時(shí)綁定的,完全取決于函數(shù)的調(diào)用位置。在本節(jié)中我們主要介紹一下幾個(gè)主要內(nèi)容: 什么是調(diào)用位置 綁定規(guī)則 this詞法 調(diào)用...

    darry 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<