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

資訊專(zhuān)欄INFORMATION COLUMN

一篇文章帶你完全理解this

Jenny_Tong / 3038人閱讀

摘要:追夢(mèng)子追夢(mèng)子通過(guò)在方法,給第一個(gè)參數(shù)添加要把添加到哪個(gè)環(huán)境中,簡(jiǎn)單來(lái)說(shuō),就會(huì)指向那個(gè)對(duì)象。追夢(mèng)子追夢(mèng)子還有一點(diǎn)就是雖然也是對(duì)象,但是在這里還是指向那個(gè)函數(shù)的實(shí)例,因?yàn)楸容^特殊。追夢(mèng)子追夢(mèng)子在嚴(yán)格版中的默認(rèn)的不再是,而是。

走在前端的大道上

本篇將自己讀過(guò)的相關(guān) this指向 的文章中,對(duì)自己有啟發(fā)的章節(jié)片段總結(jié)在這(會(huì)對(duì)原文進(jìn)行刪改),會(huì)不斷豐富提煉總結(jié)更新。

版本一 一句話(huà)
this的指向在函數(shù)定義的時(shí)候是確定不了的,只有函數(shù)執(zhí)行的時(shí)候才能確定this到底指向誰(shuí),實(shí)際上this的最終指向的是那個(gè)調(diào)用它的對(duì)象(這句話(huà)有些問(wèn)題,后面會(huì)解釋為什么會(huì)有問(wèn)題,雖然網(wǎng)上大部分的文章都是這樣說(shuō)的,雖然在很多情況下那樣去理解不會(huì)出什么問(wèn)題,但是實(shí)際上那樣理解是不準(zhǔn)確的,所以在你理解this的時(shí)候會(huì)有種琢磨不透的感覺(jué))  —— ——徹底理解js中this的指向,不必硬背。
5大規(guī)則 (1)構(gòu)造函數(shù)模式的時(shí)候,this指向新生成的實(shí)例
function Aaa(name){
  this.name= name;
  this.getName=function(){
    console.log(this.name)
  }
}
var a = new Aaa("kitty");
a.getName()        //  "kitty"
var b = new Aaa("bobo");
b.getName()        //  "bobo"

如果 new 關(guān)鍵詞出現(xiàn)在被調(diào)用函數(shù)的前面,那么JavaScript引擎會(huì)創(chuàng)建一個(gè)新的對(duì)象,被調(diào)用函數(shù)中的this指向的就是這個(gè)新創(chuàng)建的函數(shù)。

function ConstructorExample() {
    console.log(this);
    this.value = 10;
    console.log(this);
}

new ConstructorExample();

// -> ConstructorExample {}
// -> ConstructorExample { value: 10 }

構(gòu)造函數(shù)版this:

function Fn(){
    this.user = "追夢(mèng)子";
}
var a = new Fn();
console.log(a.user); //追夢(mèng)子

  這里之所以對(duì)象a可以點(diǎn)出函數(shù)Fn里面的user是因?yàn)閚ew關(guān)鍵字可以改變this的指向,將這個(gè)this指向?qū)ο骯,為什么我說(shuō)a是對(duì)象,因?yàn)橛昧薾ew關(guān)鍵字就是創(chuàng)建一個(gè)對(duì)象實(shí)例,我們這里用變量a創(chuàng)建了一個(gè)Fn的實(shí)例(相當(dāng)于復(fù)制了一份Fn到對(duì)象a里面),此時(shí)僅僅只是創(chuàng)建,并沒(méi)有執(zhí)行,而調(diào)用這個(gè)函數(shù)Fn的是對(duì)象a,那么this指向的自然是對(duì)象a,那么為什么對(duì)象a中會(huì)有user,因?yàn)槟阋呀?jīng)復(fù)制了一份Fn函數(shù)到對(duì)象a中,用了new關(guān)鍵字就等同于復(fù)制了一份。

(2)apply/call調(diào)用模式的時(shí)候,this指向apply/call方法中的第一個(gè)參數(shù)
var list1 = {name:"andy"}
var list2 = {name:"peter"}

function d(){
  console.log(this.name)
}
d.call(list1)     //  "andy" 
d.call(list2)     //  "peter" 

如果通過(guò)apply、call或者bind的方式觸發(fā)函數(shù),那么函數(shù)中的this指向傳入函數(shù)的第一個(gè)參數(shù)。

function fn() {
    console.log(this);
}

var obj = {
    value: 5
};

var boundFn = fn.bind(obj);

boundFn(); // -> { value: 5 }
fn.call(obj); // -> { value: 5 }
fn.apply(obj); // -> { value: 5 }

在沒(méi)有學(xué)之前,通常會(huì)有這些問(wèn)題。

var a = {
    user:"追夢(mèng)子",
    fn:function(){
        console.log(this.user);
    }
}
var b = a.fn;
b(); //undefined

我們是想打印對(duì)象a里面的user卻打印出來(lái)undefined是怎么回事呢?如果我們直接執(zhí)行a.fn()是可以的。

var a = {
    user:"追夢(mèng)子",
    fn:function(){
        console.log(this.user);
    }
}
a.fn(); //追夢(mèng)子

雖然這種方法可以達(dá)到我們的目的,但是有時(shí)候我們不得不將這個(gè)對(duì)象保存到另外的一個(gè)變量中,那么就可以通過(guò)以下方法。

1、call()

 

var a = {
    user:"追夢(mèng)子",
    fn:function(){
        console.log(this.user); //追夢(mèng)子
    }
}
var b = a.fn;
b.call(a);

通過(guò)在call方法,給第一個(gè)參數(shù)添加要把b添加到哪個(gè)環(huán)境中,簡(jiǎn)單來(lái)說(shuō),this就會(huì)指向那個(gè)對(duì)象。

call方法除了第一個(gè)參數(shù)以外還可以添加多個(gè)參數(shù),如下:

var a = {
    user:"追夢(mèng)子",
    fn:function(e,ee){
        console.log(this.user); //追夢(mèng)子
        console.log(e+ee); //3
    }
}
var b = a.fn;
b.call(a,1,2);
2、apply()

apply方法和call方法有些相似,它也可以改變this的指向

var a = {
    user:"追夢(mèng)子",
    fn:function(){
        console.log(this.user); //追夢(mèng)子
    }
}
var b = a.fn;
b.apply(a);

同樣apply也可以有多個(gè)參數(shù),但是不同的是,第二個(gè)參數(shù)必須是一個(gè)數(shù)組,如下:

var a = {
    user:"追夢(mèng)子",
    fn:function(e,ee){
        console.log(this.user); //追夢(mèng)子
        console.log(e+ee); //11
    }
}
var b = a.fn;
b.apply(a,[10,1]);

或者

var a = {
    user:"追夢(mèng)子",
    fn:function(e,ee){
        console.log(this.user); //追夢(mèng)子
        console.log(e+ee); //520
    }
}
var b = a.fn;
var arr = [500,20];
b.apply(a,arr);

//注意如果call和apply的第一個(gè)參數(shù)寫(xiě)的是null,那么this指向的是window對(duì)象

var a = {
    user:"追夢(mèng)子",
    fn:function(){
        console.log(this); //Window {external: Object, chrome: Object, document: document, a: Object, speechSynthesis: SpeechSynthesis…}
    }
}
var b = a.fn;
b.apply(null);
3、bind()

bind方法和call、apply方法有些不同,但是不管怎么說(shuō)它們都可以用來(lái)改變this的指向。

先來(lái)說(shuō)說(shuō)它們的不同吧。

var a = {
    user:"追夢(mèng)子",
    fn:function(){
        console.log(this.user);
    }
}
var b = a.fn;
b.bind(a);

我們發(fā)現(xiàn)代碼沒(méi)有被打印,對(duì),這就是bind和call、apply方法的不同,實(shí)際上bind方法返回的是一個(gè)修改過(guò)后的函數(shù)。

var a = {
    user:"追夢(mèng)子",
    fn:function(){
        console.log(this.user);
    }
}
var b = a.fn;
var c = b.bind(a);
console.log(c); //function() { [native code] }

那么我們現(xiàn)在執(zhí)行一下函數(shù)c看看,能不能打印出對(duì)象a里面的user

var a = {
    user:"追夢(mèng)子",
    fn:function(){
        console.log(this.user); //追夢(mèng)子
    }
}
var b = a.fn;
var c = b.bind(a);
c();

ok,同樣bind也可以有多個(gè)參數(shù),并且參數(shù)可以執(zhí)行的時(shí)候再次添加,但是要注意的是,參數(shù)是按照形參的順序進(jìn)行的。

var a = {
    user:"追夢(mèng)子",
    fn:function(e,d,f){
        console.log(this.user); //追夢(mèng)子
        console.log(e,d,f); //10 1 2
    }
}
var b = a.fn;
var c = b.bind(a,10);
c(1,2);

總結(jié):call和apply都是改變上下文中的this并立即執(zhí)行這個(gè)函數(shù),bind方法可以讓對(duì)應(yīng)的函數(shù)想什么時(shí)候調(diào)就什么時(shí)候調(diào)用,并且可以將參數(shù)在執(zhí)行的時(shí)候添加,這是它們的區(qū)別,根據(jù)自己的實(shí)際情況來(lái)選擇使用。

(3)方法調(diào)用模式的時(shí)候,this指向方法所在的對(duì)象
var a={};
a.name = "hello";
a.getName = function(){
  console.log(this.name)
}
a.getName()         //"hello"

如果一個(gè)函數(shù)是某個(gè)對(duì)象的方法,并且對(duì)象使用句點(diǎn)符號(hào)觸發(fā)函數(shù),那么this指向的就是該函數(shù)作為那個(gè)對(duì)象的屬性的對(duì)象,也就是,this指向句點(diǎn)左邊的對(duì)象。

var obj = {
    value: 5,
    printThis: function() {
      console.log(this);
    }
};

obj.printThis(); // -> { value: 5, printThis: ? }

由淺入深

例子1:
function a(){
    var user = "追夢(mèng)子";
    console.log(this.user); //undefined
    console.log(this); //Window
}
a();

按照我們上面說(shuō)的this最終指向的是調(diào)用它的對(duì)象,這里的函數(shù)a實(shí)際是被Window對(duì)象所點(diǎn)出來(lái)的,下面的代碼就可以證明。

function a(){
    var user = "追夢(mèng)子";
    console.log(this.user); //undefined
    console.log(this);  //Window
}
window.a();

和上面代碼一樣吧,其實(shí)alert也是window的一個(gè)屬性,也是window點(diǎn)出來(lái)的。

例子2:
var o = {
    user:"追夢(mèng)子",
    fn:function(){
        console.log(this.user);  //追夢(mèng)子
    }
}
o.fn();

  這里的this指向的是對(duì)象o,因?yàn)槟阏{(diào)用這個(gè)fn是通過(guò)o.fn()執(zhí)行的,那自然指向就是對(duì)象o,這里再次強(qiáng)調(diào)一點(diǎn),this的指向在函數(shù)創(chuàng)建的時(shí)候是決定不了的,在調(diào)用的時(shí)候才能決定,誰(shuí)調(diào)用的就指向誰(shuí),一定要搞清楚這個(gè)。

其實(shí)例子1和例子2說(shuō)的并不夠準(zhǔn)確,下面這個(gè)例子就可以推翻上面的理論。

如果要徹底的搞懂this必須看接下來(lái)的幾個(gè)例子

例子3:
var o = {
    user:"追夢(mèng)子",
    fn:function(){
        console.log(this.user); //追夢(mèng)子
    }
}
window.o.fn();

  這段代碼和上面的那段代碼幾乎是一樣的,但是這里的this為什么不是指向window,如果按照上面的理論,最終this指向的是調(diào)用它的對(duì)象,這里先說(shuō)個(gè)而外話(huà),window是js中的全局對(duì)象,我們創(chuàng)建的變量實(shí)際上是給window添加屬性,所以這里可以用window點(diǎn)o對(duì)象。

  這里先不解釋為什么上面的那段代碼this為什么沒(méi)有指向window,我們?cè)賮?lái)看一段代碼。

var o = {
    a:10,
    b:{
        a:12,
        fn:function(){
            console.log(this.a); //12
        }
    }
}
o.b.fn();

  這里同樣也是對(duì)象o點(diǎn)出來(lái)的,但是同樣this并沒(méi)有執(zhí)行它,那你肯定會(huì)說(shuō)我一開(kāi)始說(shuō)的那些不就都是錯(cuò)誤的嗎?其實(shí)也不是,只是一開(kāi)始說(shuō)的不準(zhǔn)確,接下來(lái)我將補(bǔ)充一句話(huà),我相信你就可以徹底的理解this的指向的問(wèn)題。

  - 情況1:如果一個(gè)函數(shù)中有this,但是它沒(méi)有被上一級(jí)的對(duì)象所調(diào)用,那么this指向的就是window,這里需要說(shuō)明的是在js的嚴(yán)格版中this指向的不是window,但是我們這里不探討嚴(yán)格版的問(wèn)題,你想了解可以自行上網(wǎng)查找。

  - 情況2:如果一個(gè)函數(shù)中有this,這個(gè)函數(shù)有被上一級(jí)的對(duì)象所調(diào)用,那么this指向的就是上一級(jí)的對(duì)象。

  - 情況3:如果一個(gè)函數(shù)中有this,這個(gè)函數(shù)中包含多個(gè)對(duì)象,盡管這個(gè)函數(shù)是被最外層的對(duì)象所調(diào)用,this指向的也只是它上一級(jí)的對(duì)象,例子3可以證明,如果不相信,那么接下來(lái)我們繼續(xù)看幾個(gè)例子。

var o = {
    a:10,
    b:{
        // a:12,
        fn:function(){
            console.log(this.a); //undefined
        }
    }
}
o.b.fn();

盡管對(duì)象b中沒(méi)有屬性a,這個(gè)this指向的也是對(duì)象b,因?yàn)閠his只會(huì)指向它的上一級(jí)對(duì)象,不管這個(gè)對(duì)象中有沒(méi)有this要的東西。

還有一種比較特殊的情況,例子4:
var o = {
    a:10,
    b:{
        a:12,
        fn:function(){
            console.log(this.a); //undefined
            console.log(this); //window
        }
    }
}
var j = o.b.fn;
j();

這里this指向的是window,是不是有些蒙了?其實(shí)是因?yàn)槟銢](méi)有理解一句話(huà),這句話(huà)同樣至關(guān)重要。

  this永遠(yuǎn)指向的是最后調(diào)用它的對(duì)象,也就是看它執(zhí)行的時(shí)候是誰(shuí)調(diào)用的,例子4中雖然函數(shù)fn是被對(duì)象b所引用,但是在將fn賦值給變量j的時(shí)候并沒(méi)有執(zhí)行所以最終指向的是window,這和例子3是不一樣的,例子3是直接執(zhí)行了fn。

  this講來(lái)講去其實(shí)就是那么一回事,只不過(guò)在不同的情況下指向的會(huì)有些不同,上面的總結(jié)每個(gè)地方都有些小錯(cuò)誤,也不能說(shuō)是錯(cuò)誤,而是在不同環(huán)境下情況就會(huì)有不同,所以我也沒(méi)有辦法一次解釋清楚,只能你慢慢地的去體會(huì)。

(4)函數(shù)調(diào)用模式的時(shí)候,this指向window
function aa(){
  console.log(this)
}
aa()         //window

如果一個(gè)函數(shù)作為FFI被調(diào)用,意味著這個(gè)函數(shù)不符合以上任意一種調(diào)用方式,this指向全局對(duì)象,在瀏覽器中,即是window。

function fn() {
    console.log(this);
}

// If called in browser:
fn(); // -> Window {stop: ?, open: ?, alert: ?, ...}

注意,第4條規(guī)則和第3條很類(lèi)似,不同的是當(dāng)函數(shù)沒(méi)有作為方法被調(diào)用時(shí),它將自動(dòng)隱式編程全局對(duì)象的屬性——window。也就是當(dāng)我們調(diào)用 fn(),可以理解為window.fn(),根據(jù)第三條規(guī)則,fn()函數(shù)中的this指向的就是window。

function fn() {
    console.log(this);
}

// In browser:
console.log(fn === window.fn); // -> true
(5) 如果出現(xiàn)上面對(duì)條規(guī)則的累加情況,則優(yōu)先級(jí)自1至4遞減,this的指向按照優(yōu)先級(jí)最高的規(guī)則判斷。

將規(guī)則應(yīng)用于實(shí)踐
看一個(gè)代碼示例,并使用上面的規(guī)則判斷this的指向。

var obj = {
    value: "hi",
    printThis: function() {
        console.log(this);
    }
};

var print = obj.printThis;

obj.printThis(); // -> {value: "hi", printThis: ?}
print(); // -> Window {stop: ?, open: ?, alert: ?, ...}

obj.prinThis() ,根據(jù)第三條規(guī)則this指向的就是obj。根據(jù)第四條規(guī)則print()是FFI,因此this指向window。

obj對(duì)象中printThis這一方法其實(shí)是函數(shù)的地址的一個(gè)引用,當(dāng)我們將obj.printThis賦值給print時(shí),print包含的也是函數(shù)的引用,和obj對(duì)象一點(diǎn)關(guān)系也沒(méi)有。obj只是碰巧擁有一個(gè)指向這個(gè)函數(shù)的引用的屬性。

當(dāng)不適用obj對(duì)象觸發(fā)函數(shù)時(shí),這個(gè)函數(shù)就是FFI。

應(yīng)用多項(xiàng)規(guī)則
當(dāng)出現(xiàn)多個(gè)上述規(guī)則時(shí),將優(yōu)先級(jí)高的“獲勝”,如果規(guī)則2和規(guī)則3同時(shí)存在,則規(guī)則2優(yōu)先:

var obj1 = {
    value: "hi",
    print: function() {
        console.log(this);
    },
};

var obj2 = { value: 17 };

obj1.print.call(obj2); // -> { value: 17 }

如果規(guī)則1和規(guī)則3同時(shí)被應(yīng)用,則規(guī)則1優(yōu)先:

var obj1 = {
    value: "hi",
    print: function() {
        console.log(this);
    },
};

new obj1.print(); // -> print {}
額外的

當(dāng)this碰到return時(shí)

function fn()  
{  
    this.user = "追夢(mèng)子";  
    return {};  
}
var a = new fn;  
console.log(a.user); //undefined

再看一個(gè)

function fn()  
{  
    this.user = "追夢(mèng)子";  
    return function(){};
}
var a = new fn;  
console.log(a.user); //undefined

再來(lái)

function fn()  
{  
    this.user = "追夢(mèng)子";  
    return 1;
}
var a = new fn;  
console.log(a.user); //追夢(mèng)子
function fn()  
{  
    this.user = "追夢(mèng)子";  
    return undefined;
}
var a = new fn;  
console.log(a.user); //追夢(mèng)子

什么意思呢?

  如果返回值是一個(gè)對(duì)象,那么this指向的就是那個(gè)返回的對(duì)象,如果返回值不是一個(gè)對(duì)象那么this還是指向函數(shù)的實(shí)例。

function fn()  
{  
    this.user = "追夢(mèng)子";  
    return undefined;
}
var a = new fn;  
console.log(a); //fn {user: "追夢(mèng)子"}

  還有一點(diǎn)就是雖然null也是對(duì)象,但是在這里this還是指向那個(gè)函數(shù)的實(shí)例,因?yàn)閚ull比較特殊。

function fn()  
{  
    this.user = "追夢(mèng)子";  
    return null;
}
var a = new fn;  
console.log(a.user); //追夢(mèng)子
在嚴(yán)格版中的默認(rèn)的this不再是window,而是undefined。 代碼中引用了庫(kù)?

有些庫(kù)會(huì)將this的指向綁定更有用的對(duì)象上,比如jQuery庫(kù),在事件處理程序中,this的指向不是全局對(duì)象而被綁定到了元素對(duì)象上。因此,如果你發(fā)現(xiàn)一些不能用上述5項(xiàng)規(guī)則解釋的情況,請(qǐng)閱讀你所使用的庫(kù)的官方文檔,找到關(guān)于該庫(kù)是如何改變this的指向的,通常通過(guò) bind 方法改變this的指向。

參考文章:
1.徹底理解js中this的指向,不必硬背。
2.javascript中this指向的規(guī)則
3.The Complete Rules to "this"
4.JavaScript中的this

版本二 上下文 vs 作用域

每個(gè)函數(shù)調(diào)用都有與之相關(guān)的作用域和上下文。首先需要澄清的問(wèn)題是上下文和作用域是不同的概念。很多人經(jīng)常將這兩個(gè)術(shù)語(yǔ)混淆。

作用域(scope) 是在運(yùn)行時(shí)代碼中的某些特定部分中變量,函數(shù)和對(duì)象的可訪(fǎng)問(wèn)性。換句話(huà)說(shuō),作用域決定了代碼區(qū)塊中變量和其他資源的可見(jiàn)性。而上下文(context)是用來(lái)指定代碼某些特定部分中 this 的值。

從根本上說(shuō),作用域是基于函數(shù)(function-based)的,而上下文是基于對(duì)象(object-based)的。換句話(huà)說(shuō),作用域是和每次函數(shù)調(diào)用時(shí)變量的訪(fǎng)問(wèn)有關(guān),并且每次調(diào)用都是獨(dú)立的。上下文總是被調(diào)用函數(shù)中關(guān)鍵字 this 的值,是調(diào)用當(dāng)前可執(zhí)行代碼的對(duì)象的引用。說(shuō)的通俗一點(diǎn)就是:this 取值,是在函數(shù)真正被調(diào)用執(zhí)行的時(shí)候確定的,而不是在函數(shù)定義的時(shí)候確定的。

全局上下文

無(wú)論是否在嚴(yán)格模式下,在全局執(zhí)行上下文中(在任何函數(shù)體外部)this 都指向全局對(duì)象。當(dāng)然具體的全局對(duì)象和宿主環(huán)境有關(guān)。

在瀏覽器中, window 對(duì)象同時(shí)也是全局對(duì)象:

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

NodeJS 中,則是 global 對(duì)象:

console.log(this); // global
函數(shù)上下文

由于其運(yùn)行期綁定的特性,JavaScript 中的 this 含義要豐富得多,它可以是全局對(duì)象、當(dāng)前對(duì)象或者任意對(duì)象,這完全取決于函數(shù)的調(diào)用方式。JavaScript 中函數(shù)的調(diào)用有以下幾種方式:作為函數(shù)調(diào)用,作為對(duì)象方法調(diào)用,作為構(gòu)造函數(shù)調(diào)用,和使用 apply 或 call 調(diào)用。下面我們將按照調(diào)用方式的不同,分別討論 this 的含義

作為函數(shù)直接調(diào)用

作為函數(shù)直接調(diào)用時(shí),要注意 2 種情況:

非嚴(yán)格模式

在非嚴(yán)格模式下執(zhí)行函數(shù)調(diào)用,此時(shí) this 默認(rèn)指向全局對(duì)象。

function f1(){
  return this;
}
//在瀏覽器中:
f1() === window;   //在瀏覽器中,全局對(duì)象是window
 
//在Node中:
f1() === global;

嚴(yán)格模式 ‘use strict’

在嚴(yán)格模式下,this 將保持他進(jìn)入執(zhí)行上下文時(shí)的值,所以下面的 this 并不會(huì)指向全局對(duì)象,而是默認(rèn)為 undefined 。

"use strict"; // 這里是嚴(yán)格模式
function test() {
  return this;
};
 
test() === undefined; // true
作為對(duì)象的方法調(diào)用

在 JavaScript 中,函數(shù)也是對(duì)象,因此函數(shù)可以作為一個(gè)對(duì)象的屬性,此時(shí)該函數(shù)被稱(chēng)為該對(duì)象的方法,在使用這種調(diào)用方式時(shí),內(nèi)部的 this 指向該對(duì)象。

var Obj = {
  prop: 37,
  getProp: function() {
    return this.prop;
  }
};
 
console.log(Obj.getProp()); // 37

上面的例子中,當(dāng) Obj.getProp() 被調(diào)用時(shí),方法內(nèi)的 this 將指向 Obj 對(duì)象。值得注意的是,這種行為根本不受函數(shù)定義方式或定義位置的影響。在前面的例子中,我們?cè)诙x對(duì)象 Obj 的同時(shí),將成員 getProp 定義了一個(gè)匿名函數(shù)。但是,我們也可以首先定義函數(shù),然后再將其附加到 Obj.getProp 。所以,下面的代碼和上面的例子是等價(jià)的:

var Obj = {
  prop: 37
};
 
function independent() {
  return this.prop;
}
 
Obj.getProp = independent;
 
console.log(Obj.getProp()); // logs 37

JavaScript 非常靈活,現(xiàn)在我們把對(duì)象的方法賦值給一個(gè)變量,然后直接調(diào)用這個(gè)函數(shù)變量又會(huì)發(fā)生什么呢?

var Obj = {
  prop: 37,
  getProp: function() {
    return this.prop;
  }
};
 
var test = Obj.getProp
console.log(test()); // undefined

可以看到,這時(shí)候 this 指向全局對(duì)象,這個(gè)例子 test 只是引用了 Obj.getProp 函數(shù),也就是說(shuō)這個(gè)函數(shù)并不作為 Obj 對(duì)象的方法調(diào)用,所以,它是被當(dāng)作一個(gè)普通函數(shù)來(lái)直接調(diào)用。因此,this 指向全局對(duì)象。

一些坑

我們來(lái)看看下面這個(gè)例子:

var prop = 0;
var Obj = {
  prop: 37,
  getProp: function() {
    setTimeout(function() {
        console.log(this.prop) // 結(jié)果是 0 ,不是37!
    },1000)
  }
};
 
Obj.getProp();

正如你所見(jiàn), setTimeout 中的 this 向了全局對(duì)象,這里不是把它當(dāng)作函數(shù)的方法使用嗎?這一點(diǎn)經(jīng)常讓很多初學(xué)者疑惑;這種問(wèn)題是很多異步回調(diào)函數(shù)中也會(huì)普遍會(huì)碰到,通常有個(gè)土辦法解決這個(gè)問(wèn)題,比如,我們可以利用 閉包 的特性來(lái)處理:

var Obj = {
  prop: 37,
  getProp: function() {
    var self = this; 
    setTimeout(function() {
        console.log(self.prop) // 37
    },1000)
  }
};
 
Obj.getProp();

其實(shí),setTimeoutsetInterval 都只是在全局上下文中執(zhí)行一個(gè)函數(shù)而已,即使是在嚴(yán)格模式下:

"use strict";
 
function foo() {
  console.log(this); // Window
}
 
setTimeout(foo, 1);

記住 setTimeoutsetInterval 都只是在全局上下文中執(zhí)行一個(gè)函數(shù)而已,因此 this 指向全局對(duì)象。 除非你實(shí)用箭頭函數(shù),Function.prototype.bind 方法等辦法修復(fù)。至于解決方案會(huì)在后續(xù)的文章中繼續(xù)討論。

作為構(gòu)造函數(shù)調(diào)用

JavaScript 支持面向?qū)ο笫骄幊?,與主流的面向?qū)ο笫骄幊陶Z(yǔ)言不同,JavaScript 并沒(méi)有類(lèi)(class)的概念,而是使用基于原型(prototype)的繼承方式。作為又一項(xiàng)約定通用的準(zhǔn)則,構(gòu)造函數(shù)以大寫(xiě)字母開(kāi)頭,提醒調(diào)用者使用正確的方式調(diào)用。

當(dāng)一個(gè)函數(shù)用作構(gòu)造函數(shù)時(shí)(使用 new 關(guān)鍵字),它的 this 被綁定到正在構(gòu)造的新對(duì)象,也就是我們常說(shuō)的實(shí)例化出來(lái)的對(duì)象。

function Person(name) {
  this.name = name;
}
 
var p = new Person("愚人碼頭");
console.log(p.name); // "愚人碼頭"

幾個(gè)陷阱

如果構(gòu)造函數(shù)具有返回對(duì)象的 return 語(yǔ)句,則該返回對(duì)象將是 new 表達(dá)式的結(jié)果。

function Person(name) {
  this.name = name;
  return { title : "前端開(kāi)發(fā)" };
}
 
var p = new Person("愚人碼頭");
console.log(p.name); // undefined
console.log(p.title); // "前端開(kāi)發(fā)"

相應(yīng)的,JavaScript 中的構(gòu)造函數(shù)也很特殊,如果不使用 new 調(diào)用,則和普通函數(shù)一樣, this 仍然執(zhí)行全局:

function Person(name) {
  this.name = name;
  console.log(this); // Window 
}
 
var p = Person("愚人碼頭");
箭頭函數(shù)中的 this

在箭頭函數(shù)中,this 與封閉詞法上下文的 this 保持一致,也就是說(shuō)由上下文確定。

var obj = {
    x: 10,
    foo: function() {
        var fn = () => {
            return () => {
                return () => {
                    console.log(this);      //{x: 10, foo: ?} 即 obj
                    console.log(this.x);    //10
                }
            }
        }
        fn()()();
    }
}
obj.foo();

obj.foo 是一個(gè)匿名函數(shù),無(wú)論如何, 這個(gè)函數(shù)中的 this 指向它被創(chuàng)建時(shí)的上下文(在上面的例子中,就是 obj 對(duì)象)。這同樣適用于在其他函數(shù)中創(chuàng)建的箭頭函數(shù):這些箭頭函數(shù)的this 被設(shè)置為外層執(zhí)行上下文。

// 創(chuàng)建一個(gè)含有bar方法的obj對(duì)象,bar返回一個(gè)函數(shù),這個(gè)函數(shù)返回它自己的this,
// 這個(gè)返回的函數(shù)是以箭頭函數(shù)創(chuàng)建的,所以它的this被永久綁定到了它外層函數(shù)的this。
// bar的值可以在調(diào)用中設(shè)置,它反過(guò)來(lái)又設(shè)置返回函數(shù)的值。
var obj = {
    bar: function() {
        var x = (() => this);
        return x;
    }
};
 
// 作為obj對(duì)象的一個(gè)方法來(lái)調(diào)用bar,把它的this綁定到obj。
// x所指向的匿名函數(shù)賦值給fn。
var fn = obj.bar();
 
// 直接調(diào)用fn而不設(shè)置this,通常(即不使用箭頭函數(shù)的情況)默認(rèn)為全局對(duì)象,若在嚴(yán)格模式則為undefined
console.log(fn() === obj); // true
 
// 但是注意,如果你只是引用obj的方法,而沒(méi)有調(diào)用它(this是在函數(shù)調(diào)用過(guò)程中設(shè)置的)
var fn2 = obj.bar;
// 那么調(diào)用箭頭函數(shù)后,this指向window,因?yàn)樗鼜?bar 繼承了this。
console.log(fn2()() == window); // true

在上面的例子中,一個(gè)賦值給了 obj.bar 的函數(shù)(稱(chēng)為匿名函數(shù) A),返回了另一個(gè)箭頭函數(shù)(稱(chēng)為匿名函數(shù) B)。因此,函數(shù)B的this被永久設(shè)置為 obj.bar(函數(shù)A)被調(diào)用時(shí)的 this 。當(dāng)返回的函數(shù)(函數(shù)B)被調(diào)用時(shí),它this始終是最初設(shè)置的。在上面的代碼示例中,函數(shù)B的 this 被設(shè)置為函數(shù)A的 this ,即 obj,所以它仍然設(shè)置為 obj,即使以通常將 this 設(shè)置為 undefined 或全局對(duì)象(或者如前面示例中全局執(zhí)行上下文中的任何其他方法)進(jìn)行調(diào)用。

填坑

我們回到上面 setTimeout 的坑:

var prop = 0;
var Obj = {
  prop: 37,
  getProp: function() {
    setTimeout(function() {
        console.log(this.prop) // 結(jié)果是 0 ,不是37!
    },1000)
  }
};
 
Obj.getProp();

通常情況我,我們?cè)谶@里期望輸出的結(jié)果是 37 ,用箭頭函數(shù)解決這個(gè)問(wèn)題相當(dāng)簡(jiǎn)單:

var Obj = {
  prop: 37,
  getProp: function() {
    setTimeout(() => {
        console.log(this.prop) // 37
    },1000)
  }
};
 
Obj.getProp();
原型鏈中的 this

相同的概念在定義在原型鏈中的方法也是一致的。如果該方法存在于一個(gè)對(duì)象的原型鏈上,那么 this 指向的是調(diào)用這個(gè)方法的對(duì)象,就好像該方法本來(lái)就存在于這個(gè)對(duì)象上。

var o = {
  f : function(){ 
    return this.a + this.b; 
  }
};
var p = Object.create(o);
p.a = 1;
p.b = 4;
 
console.log(p.f()); // 5

在這個(gè)例子中,對(duì)象 p 沒(méi)有屬于它自己的f屬性,它的f屬性繼承自它的原型。但是這對(duì)于最終在 o 中找到 f 屬性的查找過(guò)程來(lái)說(shuō)沒(méi)有關(guān)系;查找過(guò)程首先從 p.f 的引用開(kāi)始,所以函數(shù)中的 this 指向 p 。也就是說(shuō),因?yàn)閒是作為p的方法調(diào)用的,所以它的this 指向了 p 。這是 JavaScript 的原型繼承中的一個(gè)有趣的特性。

你也會(huì)看到下面這種形式的老代碼,道理是一樣的:

function Person(name) {
  this.name = name;
}
Person.prototype = {
  getName:function () {
    return this.name
  }
};
var p = new Person("愚人碼頭");
console.log(p.getName()); // "愚人碼頭"
getter 與 setter 中的 this

再次,相同的概念也適用時(shí)的函數(shù)作為一個(gè) getter 或者 一個(gè) setter 調(diào)用。用作 getter 或 setter 的函數(shù)都會(huì)把 this 綁定到正在設(shè)置或獲取屬性的對(duì)象。

function sum() {
  return this.a + this.b + this.c;
}
 
var o = {
  a: 1,
  b: 2,
  c: 3,
  get average() {
    return (this.a + this.b + this.c) / 3;
  }
};
 
Object.defineProperty(o, "sum", {
    get: sum, enumerable: true, configurable: true});
 
console.log(o.average, o.sum); // logs 2, 6

注:Object.defineProperty() 顧名思義,為對(duì)象定義屬性,方法會(huì)直接在一個(gè)對(duì)象上定義一個(gè)新屬性,或者修改一個(gè)對(duì)象的現(xiàn)有屬性, 并返回這個(gè)對(duì)象。是ES5的屬性, 支持IE8以上。

Object.defineProperty(obj, prop, descriptor)

參數(shù)

object 必需。 要在其上添加或修改屬性的對(duì)象。 這可能是一個(gè)本機(jī) JavaScript對(duì)象(即用戶(hù)定義的對(duì)象或內(nèi)置對(duì)象)或 DOM 對(duì)象。

propertyname 必需。 一個(gè)包含屬性名稱(chēng)的字符串。

descriptor 必需。 屬性描述符。 它可以針對(duì)數(shù)據(jù)屬性或訪(fǎng)問(wèn)器屬性。

在js中我們可以通過(guò)下面這幾種方法定義屬性

// (1) define someOne property name
someOne.name = "cover";
//or use (2) 
someOne["name"] = "cover";
// or use (3) defineProperty
Object.defineProperty(someOne, "name", {
    value : "cover"
})

屬性的狀態(tài)設(shè)置
其中descriptor的參數(shù)值得我們關(guān)注下,該屬性可設(shè)置的值有:
【value】 屬性的值,默認(rèn)為 undefined。
【writable】 該屬性是否可寫(xiě),如果設(shè)置成 false,則任何對(duì)該屬性改寫(xiě)的操作都無(wú)效(但不會(huì)報(bào)錯(cuò)),對(duì)于像前面例子中直接在對(duì)象上定義的屬性,這個(gè)屬性該特性默認(rèn)值為為 true。

var someOne = { };
Object.defineProperty(someOne, "name", {
    value:"coverguo" , //由于設(shè)定了writable屬性為false 導(dǎo)致這個(gè)量不可以修改
    writable: false 
});  
console.log(someOne.name); // 輸出 coverguo
someOne.name = "linkzhu";
console.log(someOne.name); // 輸出coverguo

【configurable]】如果為false,則任何嘗試刪除目標(biāo)屬性或修改屬性以下特性(writable, configurable, enumerable)的行為將被無(wú)效化,對(duì)于像前面例子中直接在對(duì)象上定義的屬性,這個(gè)屬性該特性默認(rèn)值為為 true。

var someOne = { };
Object.defineProperty(someOne, "name", {
    value:"coverguo" ,
    configurable: false 
});  
delete someOne.name; 
console.log(someOne.name);// 輸出 coverguo
someOne.name = "linkzhu";
console.log(someOne.name); // 輸出coverguo

【enumerable】 是否能在for-in循環(huán)中遍歷出來(lái)或在Object.keys中列舉出來(lái)。對(duì)于像前面例子中直接在對(duì)象上定義的屬性,這個(gè)屬性該特性默認(rèn)值為為 true。
注意 在調(diào)用Object.defineProperty()方法時(shí),如果不指定, configurable, enumerable, writable特性的默認(rèn)值都是false,這跟之前所 說(shuō)的對(duì)于像前面例子中直接在對(duì)象上定義的屬性,這個(gè)特性默認(rèn)值為為 true并不沖突,如下代碼所示:

//調(diào)用Object.defineProperty()方法時(shí),如果不指定
var someOne = { };
someOne.name = "coverguo";
console.log(Object.getOwnPropertyDescriptor(someOne, "name"));
//輸出 Object {value: "coverguo", writable: true, enumerable: true, configurable: true}

//直接在對(duì)象上定義的屬性,這個(gè)特性默認(rèn)值為為 true
var otherOne = {};
Object.defineProperty(otherOne, "name", {
    value:"coverguo" 
});  
console.log(Object.getOwnPropertyDescriptor(otherOne, "name"));
//輸出 Object {value: "coverguo", writable: false, enumerable: false, configurable: false}

【get】一旦目標(biāo)對(duì)象訪(fǎng)問(wèn)該屬性,就會(huì)調(diào)用這個(gè)方法,并返回結(jié)果。默認(rèn)為 undefined。
【set】 一旦目標(biāo)對(duì)象設(shè)置該屬性,就會(huì)調(diào)用這個(gè)方法。默認(rèn)為 undefined。
從上面,可以得知,我們可以通過(guò)使用Object.defineProperty,來(lái)定義和控制一些特殊的屬性,如屬性是否可讀,屬性是否可枚舉,甚至修改屬性的修改器(setter)和獲取器(getter)
那什么場(chǎng)景和地方適合使用到特殊的屬性呢?

從上面,可以得知,我們可以通過(guò)使用Object.defineProperty,來(lái)定義和控制一些特殊的屬性,如屬性是否可讀,屬性是否可枚舉,甚至修改屬性的修改器(setter)和獲取器(getter)

實(shí)際運(yùn)用
在一些框架,如vue、express、qjs等,經(jīng)常會(huì)看到對(duì)Object.defineProperty的使用。那這些框架是如何使用呢?

MVVM中數(shù)據(jù)‘雙向綁定’實(shí)現(xiàn)
待補(bǔ)充
優(yōu)化對(duì)象獲取和修改屬性方式
這個(gè)優(yōu)化對(duì)象獲取和修改屬性方式,是什么意思呢? 過(guò)去我們?cè)谠O(shè)置dom節(jié)點(diǎn)transform時(shí)是這樣的。

//加入有一個(gè)目標(biāo)節(jié)點(diǎn), 我們想設(shè)置其位移時(shí)是這樣的
var targetDom = document.getElementById("target");
var transformText = "translateX(" + 10 + "px)";
targetDom.style.webkitTransform = transformText;
targetDom.style.transform = transformText;

通過(guò)上面,可以看到如果頁(yè)面是需要許多動(dòng)畫(huà)時(shí),我們這樣編寫(xiě)transform屬性是十分蛋疼的。
但如果通過(guò)Object.defineProperty, 我們則可以

//這里只是簡(jiǎn)單設(shè)置下translateX的屬性,其他如scale等屬性可自己去嘗試

Object.defineProperty(dom, "translateX", {
set: function(value) {
         var transformText = "translateX(" + value + "px)";
        dom.style.webkitTransform = transformText;
        dom.style.transform = transformText;
}
//這樣再后面調(diào)用的時(shí)候, 十分簡(jiǎn)單
dom.translateX = 10;
dom.translateX = -10;
//甚至可以拓展設(shè)置如scale, originX, translateZ,等各個(gè)屬性,達(dá)到下面的效果
dom.scale = 1.5;  //放大1.5倍
dom.originX = 5;  //設(shè)置中心點(diǎn)X
}

上面只是個(gè)簡(jiǎn)單的版本,并不是最合理的寫(xiě)法,但主要是為了說(shuō)明具體的意圖和方法
增加屬性獲取和修改時(shí)的信息
如在Express4.0中,該版本去除了一些舊版本的中間件,為了讓用戶(hù)能夠更好地發(fā)現(xiàn),其有下面這段代碼,通過(guò)修改get屬性方法,讓用戶(hù)調(diào)用廢棄屬性時(shí)拋錯(cuò)并帶上自定義的錯(cuò)誤信息。

[
  "json",
  "urlencoded",
  "bodyParser",
  "compress",
  "cookieSession",
  "session",
  "logger",
  "cookieParser",
  "favicon",
  "responseTime",
  "errorHandler",
  "timeout",
  "methodOverride",
  "vhost",
  "csrf",
  "directory",
  "limit",
  "multipart",
  "staticCache",
].forEach(function (name) {
  Object.defineProperty(exports, name, {
    get: function () {
      throw new Error("Most middleware (like " + name + ") is no longer bundled with Express and must be installed separately. Please see https://github.com/senchalabs/connect#middleware.");
    },
    configurable: true
  });
});
作為一個(gè)DOM事件處理函數(shù)

當(dāng)函數(shù)被用作事件處理函數(shù)時(shí),它的 this 指向觸發(fā)事件的元素(一些瀏覽器在使用非addEventListener 的函數(shù)動(dòng)態(tài)添加監(jiān)聽(tīng)函數(shù)時(shí)不遵守這個(gè)約定)。

// 被調(diào)用時(shí),將關(guān)聯(lián)的元素變成藍(lán)色
function bluify(e){
  console.log(this === e.currentTarget); // 總是 true
 
  // 當(dāng) currentTarget 和 target 是同一個(gè)對(duì)象是為 true
  console.log(this === e.target);        
  this.style.backgroundColor = "#A5D9F3";
}
 
// 獲取文檔中的所有元素的列表
var elements = document.getElementsByTagName("*");
 
// 將bluify作為元素的點(diǎn)擊監(jiān)聽(tīng)函數(shù),當(dāng)元素被點(diǎn)擊時(shí),就會(huì)變成藍(lán)色
for(var i=0 ; i < elements.length; i++){
  elements[i].addEventListener("click", bluify, false);
}
作為一個(gè)內(nèi)聯(lián)事件處理函數(shù)

當(dāng)代碼被內(nèi)聯(lián)on-event 處理函數(shù)調(diào)用時(shí),它的this指向監(jiān)聽(tīng)器所在的DOM元素:

上面的 alert 會(huì)顯示 button 。注意只有外層代碼中的 this 是這樣設(shè)置的:

在這種情況下,沒(méi)有設(shè)置內(nèi)部函數(shù)的 this,所以它指向 global/window 對(duì)象(即非嚴(yán)格模式下調(diào)用的函數(shù)未設(shè)置 this 時(shí)指向的默認(rèn)對(duì)象)。

使用 apply 或 call 調(diào)用

JavaScript 中函數(shù)也是對(duì)象,對(duì)象則有方法,apply 和 call 就是函數(shù)對(duì)象的方法。這兩個(gè)方法異常強(qiáng)大,他們?cè)试S切換函數(shù)執(zhí)行的上下文環(huán)境(context),即 this 綁定的對(duì)象。很多 JavaScript 中的技巧以及類(lèi)庫(kù)都用到了該方法。讓我們看一個(gè)具體的例子:

function Point(x, y){ 
   this.x = x; 
   this.y = y; 
   this.moveTo = function(x, y){ 
       this.x = x; 
       this.y = y; 
   } 
} 
 
var p1 = new Point(0, 0); 
p1.moveTo(1, 1); 
console.log(p1.x,p1.y); //1 1
 
var p2 = {x: 0, y: 0}; 
p1.moveTo.apply(p2, [10, 10]);
console.log(p2.x,p2.y); //10 10

在上面的例子中,我們使用構(gòu)造函數(shù)生成了一個(gè)對(duì)象 p1,該對(duì)象同時(shí)具有 moveTo 方法;使用對(duì)象字面量創(chuàng)建了另一個(gè)對(duì)象 p2,我們看到使用 apply 可以將 p1 的方法 apply 到 p2 上,這時(shí)候 this 也被綁定到對(duì)象 p2 上。另一個(gè)方法 call 也具備同樣功能,不同的是最后的參數(shù)不是作為一個(gè)數(shù)組統(tǒng)一傳入,而是分開(kāi)傳入的:

function Point(x, y){ 
   this.x = x; 
   this.y = y; 
   this.moveTo = function(x, y){ 
       this.x = x; 
       this.y = y; 
   } 
} 
 
var p1 = new Point(0, 0); 
p1.moveTo(1, 1); 
console.log(p1.x,p1.y); //1 1
 
var p2 = {x: 0, y: 0}; 
p1.moveTo.call(p2, 10, 10); // 只是參數(shù)不同
console.log(p2.x,p2.y); //10 10
.bind() 方法

ECMAScript 5 引入了 Function.prototype.bind 。調(diào)用 f.bind(someObject) 會(huì)創(chuàng)建一個(gè)與 f 具有相同函數(shù)體和作用域的函數(shù),但是在這個(gè)新函數(shù)中,this 將永久地被綁定到了 bind 的第一個(gè)參數(shù),無(wú)論這個(gè)函數(shù)是如何被調(diào)用的。

function f(){
  return this.a;
}
 
//this被固定到了傳入的對(duì)象上
var g = f.bind({a:"azerty"});
console.log(g()); // azerty
 
var h = g.bind({a:"yoo"}); //bind只生效一次!
console.log(h()); // azerty
 
var o = {a:37, f:f, g:g, h:h};
console.log(o.f(), o.g(), o.h()); // 37, azerty, azerty

填坑

上面我們已經(jīng)講了使用箭頭函數(shù)填 setTimeout 的坑,這次我們使用 bind 方法來(lái)試試:

var prop = 0;
var Obj = {
  prop: 37,
  getProp: function() {
    setTimeout(function() {
        console.log(this.prop) // 37
    }.bind(Obj),1000)
  }
};
 
Obj.getProp();

同樣可以填坑,但是看上去沒(méi)有使用箭頭函數(shù)來(lái)的優(yōu)雅。

Vue實(shí)例里this

vue文檔里的原話(huà):

All lifecycle hooks are called with their "this" context pointing to the Vue instance invoking it.

意思是:在Vue所有的生命周期鉤子方法(如created,mounted, updated以及destroyed)里使用this,this指向調(diào)用它的Vue實(shí)例。

示例分析




    
    
    
    

示例定義了兩個(gè)message。一個(gè)是全局變量,即window.message,它的值為英文“Hello!”。另外一個(gè)是vue實(shí)例的數(shù)據(jù)message,它的值為中文的“你好!”。

運(yùn)行示例,在瀏覽器得到:

第一個(gè)輸出英文"Hello!”,第二個(gè)輸出中文“你好!”。這說(shuō)明了showMessage1()里的this指的是window,而showMessage2()里的this指的是vue實(shí)例。

//created

created: function() {
  this.showMessage1();    //this 1
  this.showMessage2();   //this 2
}

created函數(shù)為vue實(shí)例的鉤子方法,它里面使用的this指的是vue實(shí)例。

//showMessage1()

showMessage1:function(){
    setTimeout(function() {
       document.getElementById("id1").innerText = this.message;  //this 3
    }, 10)
}

對(duì)于普通函數(shù)(包括匿名函數(shù)),this指的是直接的調(diào)用者,在非嚴(yán)格模式下,如果沒(méi)有直接調(diào)用者,this指的是window。showMessage1()里setTimeout使用了匿名函數(shù),this指向window。

//showMessage2()

showMessage2:function() {
    setTimeout(() => {
       document.getElementById("id2").innerText = this.message;  //this 4
    }, 10)
}

箭頭函數(shù)是沒(méi)有自己的this,在它內(nèi)部使用的this是由它定義的宿主對(duì)象決定。showMessage2()里定義的箭頭函數(shù)宿主對(duì)象為vue實(shí)例,所以它里面使用的this指向vue實(shí)例。

綁定vue實(shí)例到this的方法

為了避免this指向出現(xiàn)歧義,有兩種方法綁定this。

使用bind

showMessage1()可以改為:

showMessage1:function(){
    setTimeout(function() {
       document.getElementById("id1").innerText = this.message;  //this 3
    }.bind(this), 10)
}

對(duì)setTimeout()里的匿名函數(shù)使用bind()綁定到vue實(shí)例的this。這樣在匿名函數(shù)內(nèi)的this也為vue實(shí)例。

賦值給另一個(gè)變量

showMessage1()也可以改為

showMessage1:function(){
    var self = this;
    setTimeout(function() {
       document.getElementById("id1").innerText = self.message;  //改為self
    }.bind(this), 10)
}

這里吧表示vue實(shí)例的this賦值給變量self。在使用到this的地方改用self引用。

參考文章:
1.全面理解 JavaScript 中的 this
2.不會(huì)Object.defineProperty你就out了
3.10道典型的JavaScript面試題

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

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

相關(guān)文章

  • 手挽手帶你學(xué)React:二檔 React生命周期以及組件開(kāi)發(fā)

    摘要:手挽手帶你學(xué)入門(mén)二檔組件開(kāi)發(fā)的開(kāi)始,合理運(yùn)用生命周期和組件,能夠讓你的開(kāi)發(fā)變地流利又這篇文章帶你學(xué)會(huì)創(chuàng)建組件,運(yùn)用組建。 手挽手帶你學(xué)React入門(mén)二檔,組件開(kāi)發(fā)的開(kāi)始,合理運(yùn)用生命周期和組件,能夠讓你的開(kāi)發(fā)變地流利又happy,這篇文章帶你學(xué)會(huì)創(chuàng)建組件,運(yùn)用組建。學(xué)起來(lái)吧! React 組件生命周期 學(xué)習(xí)React,生命周期很重要,我們了解完生命周期的各個(gè)組件,對(duì)寫(xiě)高性能組件會(huì)有很大...

    izhuhaodev 評(píng)論0 收藏0
  • 文章帶你理解原型和原型鏈

    摘要:上面的代碼,運(yùn)行以后,我們可以看到因?yàn)榈脑褪侵赶虻膶?shí)例上的,所以可以訪(fǎng)問(wèn)他的屬性值,那如果我不想讓訪(fǎng)問(wèn)的構(gòu)造函數(shù)里聲明的屬性值,那怎么辦呢只需要將指向的原型而不是實(shí)例就行了。 走在前端的大道上 本篇將自己讀過(guò)的相關(guān) javascript原型和原型鏈 文章中,對(duì)自己有啟發(fā)的章節(jié)片段總結(jié)在這(會(huì)對(duì)原文進(jìn)行刪改),會(huì)不斷豐富提煉總結(jié)更新。 文章——深入理解javascript之原型 一般的...

    yintaolaowanzi 評(píng)論0 收藏0
  • 圖文 視頻雙管齊下,帶你全面徹底理解Retrofit源碼,Android開(kāi)發(fā)五年

    摘要:協(xié)程的判斷條件下面我們來(lái)著重看下的源碼,因?yàn)閺倪@里開(kāi)始就涉及到協(xié)程的判斷。第二點(diǎn)是關(guān)鍵點(diǎn),用來(lái)判斷該方法的調(diào)用是否使用到了協(xié)程。原理我們先來(lái)看下使用協(xié)程是怎么寫(xiě)的這是一個(gè)標(biāo)準(zhǔn)的協(xié)程寫(xiě)法,然后我們?cè)偬子蒙厦娴臈l件,發(fā)現(xiàn)完全匹配不到。 第一眼看,跟我之前印象中的有點(diǎn)區(qū)別(也不知道是什么版本),return的時(shí)候居然...

    不知名網(wǎng)友 評(píng)論0 收藏0
  • 文章帶你了解如何用Planting 為測(cè)試工程師開(kāi)發(fā)的部署框架

    摘要:是一個(gè)為測(cè)試工程師開(kāi)發(fā)的部署框架,使用語(yǔ)言編寫(xiě),為了解決測(cè)試團(tuán)隊(duì)在測(cè)試過(guò)程中的部署問(wèn)題。部署執(zhí)行方式簡(jiǎn)單,支持命令行與自動(dòng)化測(cè)試可緊密合作作為一個(gè)為測(cè)試工程師開(kāi)發(fā)的部署框架,通過(guò)命令行進(jìn)行自動(dòng)化部署是第一選擇。 ...

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

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

0條評(píng)論

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