1.背景介紹
this是Javascript語(yǔ)言的一個(gè)關(guān)鍵字。它代表函數(shù)運(yùn)行時(shí),自動(dòng)生成的一個(gè)內(nèi)部對(duì)象。
this是動(dòng)態(tài)綁定的,它可以是全局對(duì)象、當(dāng)前對(duì)象或者任意對(duì)象(這取決于函數(shù)的調(diào)用方式)。這就導(dǎo)致了this具備了多重含義,可以使得javascript更靈活的使用。但是,帶來(lái)了靈活性的同時(shí)也會(huì)給我們初學(xué)者帶來(lái)不少困惑。
2.知識(shí)剖析
全局環(huán)境中的this
functiontest(){console.log(this);? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? ? test();
總結(jié):在全局作用域中它的 this 執(zhí)行當(dāng)前的全局對(duì)象(瀏覽器端是 Window,node 中是 global)
嚴(yán)格模式 ‘use strict’下的this
'use strict';functiontest(){console.log(this);? ? ? ? ? ? ? ? ? };? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? test();// undefined
在javascritp中,不一定只有對(duì)象方法的上下文中才有this, 全局函數(shù)調(diào)用和其他的幾種不同的上下文中也有this指代。 它可以是全局對(duì)象、當(dāng)前對(duì)象或者任意對(duì)象,這完全取決于函數(shù)的調(diào)用方式。JavaScript 中函數(shù)的調(diào)用有以下幾種方式:作為對(duì)象方法調(diào)用,作為函數(shù)調(diào)用,作為構(gòu)造函數(shù)調(diào)用,和使用 apply 或 call 調(diào)用。
原因:this 并不會(huì)指向全局,而是 undefined,這樣的做法是為了消除 js 中一些不嚴(yán)謹(jǐn)?shù)男袨?/p>
1.作為對(duì)象方法調(diào)用:this 被自然綁定到該對(duì)象,也就是說(shuō)this就指這個(gè)上級(jí)對(duì)象
varpoint = {? ? ? ? ? ? ? ? x :0,? ? ? ? ? ? ? ? y :0,? ? ? ? ? ? ? ? moveTo :function(x, y){this.x =this.x + x;this.y =this.y + y;? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? };? ? ? ? ? ? ? ? point.moveTo(1,1)//this 綁定到當(dāng)前對(duì)象,即 point 對(duì)象
2.作為函數(shù)調(diào)用:this被綁定到全局對(duì)象
functionmakeNoSense(x){this.x = x;? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? ? makeNoSense(5);? ? ? ? ? ? ? ? ? x;// x 已經(jīng)成為一個(gè)值為 5 的全局變量
3.作為構(gòu)造函數(shù)調(diào)用:this 綁定到新創(chuàng)建的對(duì)象上,也就是說(shuō)this就指這個(gè)新對(duì)象
functionPoint(x, y){this.x = x;this.y = y;? ? ? ? ? ? ? ? }
注:構(gòu)造函數(shù)不使用new調(diào)用,則和普通函數(shù)一樣。一般地,構(gòu)造函數(shù)首字母大寫(xiě)
4.使用 apply 或 call 調(diào)用:在 JavaScript 中函數(shù)也是對(duì)象,對(duì)象則有方法,apply 和 call 就是函數(shù)對(duì)象的方法。
functionPoint(x, y){this.x = x;this.y = y;this.moveTo =function(x, y){this.x = x;this.y = y;? ? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? }varp1 =newPoint(0,0);varp2 = {x:0, y:0};? ? ? ? ? ? ? ? ? ? p1.moveTo(1,1);? ? ? ? ? ? ? ? ? ? p1.moveTo.apply(p2, [10,10]);
3、常見(jiàn)問(wèn)題
問(wèn)題一
varobj = {? ? ? ? ? ? ? ? ? name:'qiutc',? ? ? ? ? ? ? ? ? foo:function(){console.log(this);? ? ? ? ? ? ? ? ? },? ? ? ? ? ? ? ? ? foo2:function(){console.log(this);? ? ? ? ? ? ? ? ? ? setTimeout(this.foo,1000);? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? obj.foo2();
現(xiàn)象:兩次打印的this不一樣
問(wèn)題二
'use strict';functionfoo(){console.log(this);? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? setTimeout(foo,1);// window
現(xiàn)象:加了嚴(yán)格模式,foo 調(diào)用也沒(méi)有指定 this,應(yīng)該是出來(lái)undefined,但是這里仍然出現(xiàn)了全局對(duì)象
4、解決方案
問(wèn)題一可以這么這么解決:利用 閉包 的特性來(lái)處理
var obj = {name:'qiutc',? ? ? ? ? ? ? ? ? ? ? foo: function() {? ? ? ? ? ? ? ? ? ? ? ? console.log(this);? ? ? ? ? ? ? ? ? ? ? },? ? ? ? ? ? ? ? ? ? ? foo2: function() {? ? ? ? ? ? ? ? ? ? ? ? console.log(this);? ? ? ? ? ? ? ? ? ? ? ? var_this= this;? ? ? ? ? ? ? ? ? ? ? ? setTimeout(function() {? ? ? ? ? ? ? ? ? ? ? ? ? console.log(this);// Windowconsole.log(_this);// Object {name: "qiutc"}},1000);? ? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? obj.foo2();
可以看到直接用 this 仍然是 Window;因?yàn)?foo2 中的 this 是指向 obj,我們可以先用一個(gè)變量 _this 來(lái)儲(chǔ)存,然后在回調(diào)函數(shù)中使用 _this,就可以指向當(dāng)前的這個(gè)對(duì)象了
問(wèn)題二
setTimeout 方法在調(diào)用傳入函數(shù)的時(shí)候,如果這個(gè)函數(shù)沒(méi)有指定了的 this,那么它會(huì)做一個(gè)隱式的操作—-自動(dòng)地注入全局上下文,等同于調(diào)用 foo.apply(window) 而非 foo();
5、編碼實(shí)戰(zhàn)
問(wèn)題一可以這么這么解決:利用 閉包 的特性來(lái)處理 var obj = { name: 'qiutc', foo: function() { console.log(this); }, foo2: function() { console.log(this); var _this = this; setTimeout(function() { console.log(this); // Window console.log(_this); // Object {name: "qiutc"} }, 1000); } } obj.foo2(); 可以看到直接用 this 仍然是 Window;因?yàn)?foo2 中的 this 是指向 obj,我們可以先用一個(gè)變量 _this 來(lái)儲(chǔ)存,然后在回調(diào)函數(shù)中使用 _this,就可以指向當(dāng)前的這個(gè)對(duì)象了
對(duì)于內(nèi)部函數(shù),即聲明在另外一個(gè)函數(shù)體內(nèi)的函數(shù),這種綁定到全局對(duì)象的方式會(huì)產(chǎn)生另外一個(gè)問(wèn)題。我們?nèi)匀灰郧懊嫣岬?的 point 對(duì)象為例,這次我們希望在 moveTo 方法內(nèi)定義兩個(gè)函數(shù),分別將 x,y 坐標(biāo)進(jìn)行平移。結(jié)果可能出乎大家意 料,不僅 point 對(duì)象沒(méi)有移動(dòng),反而多出兩個(gè)全局變量 x,y
這屬于 JavaScript 的設(shè)計(jì)缺陷,正確的設(shè)計(jì)方式是內(nèi)部函數(shù)的 this 應(yīng)該綁定到其外層函數(shù)對(duì)應(yīng)的對(duì)象上,為了規(guī)避這一設(shè) 計(jì)缺陷,聰明的 JavaScript 程序員想出了變量替代的方法,約定俗成,該變量一般被命名為 that。
6.擴(kuò)展思考
問(wèn)題:如何理解this?
當(dāng)一個(gè)函數(shù)被調(diào)用時(shí),擁有它的object會(huì)作為this傳入。在全局下,就是window or global,其他時(shí)候就是相應(yīng)的object。 也可以看到,call和apply就是利用這一點(diǎn)實(shí)現(xiàn)更改this 值的
7.參考文獻(xiàn)