什么是this
this是JS中一個(gè)非常重要的關(guān)鍵字澜公。this 就是你 call 一個(gè)函數(shù)時(shí)尾组,傳入的 context粟矿。任何形式的函數(shù)調(diào)用都可以寫成call形式污尉,傳入的第一個(gè)參數(shù)就是this膀哲。
f(a,b) 等價(jià)于 f.call(undefined , a , b)
f.m.n(a,b) 等價(jià)于 f.m.n.call(f.m , a , b)
fn.call(context , p1 , p2)
所以當(dāng)我們無(wú)法確定this時(shí)我們可以轉(zhuǎn)換成call形式來確認(rèn)this。
如何確定this
通常我們確定this會(huì)用以下方式
1被碗、console.log(this)
2某宪、查看API源代碼
3、查看API相關(guān)文檔
this的使用
全局變量
function f() {
console.log(this); // window
}
var a=1
function f() {
console.log(this.a);
}
f()
//1
對(duì)象的方法
當(dāng)A對(duì)象的方法被賦予B對(duì)象蛮放,該方法中的this就從指向A對(duì)象變成了指向B對(duì)象。所以要特別小心奠宜,將某個(gè)對(duì)象的方法賦值給另一個(gè)對(duì)象包颁,會(huì)改變this的指向。
var obj ={
foo: function () {
console.log(this);
}
};
obj.foo() // obj
但是压真,只有這一種用法(直接在obj對(duì)象上調(diào)用foo方法)娩嚼,this指向obj;其他用法時(shí)滴肿,this都指向代碼塊當(dāng)前所在對(duì)象(瀏覽器為window對(duì)象)岳悟。
(obj.foo = obj.foo)()
/ 等價(jià)于 /
(obj.foo = function () {
console.log(this);
})()
//window
可以這樣理解,obj和obj.foo儲(chǔ)存在兩個(gè)內(nèi)存地址泼差,簡(jiǎn)稱為M1和M2贵少。只有obj.foo()這樣調(diào)用時(shí),是從M1調(diào)用M2堆缘,因此this指向obj滔灶。但是,上面情況是直接取出M2進(jìn)行運(yùn)算吼肥,然后就在全局環(huán)境執(zhí)行運(yùn)算結(jié)果(還是M2)录平,因此this指向全局環(huán)境麻车。
避免多層this
由于this的指向是不確定的,所以切勿在函數(shù)中包含多層的this斗这。
var o = {
f1: function () {
console.log(this);
var f2 = function () {
console.log(this);
}();
}
}
o.f1()
// Object
// Window
上面代碼等價(jià)于
var temp = function () {
console.log(this);
};
var o = {
f1: function () {
console.log(this);
var f2 = temp();
}
}
當(dāng)我們把代碼修改為
var o = {
f1: function() {
console.log(this);
var that = this;
var f2 = function() {
console.log(that);
}();
}
}
o.f1()
// Object
// Object
上面代碼定義了變量that动猬,固定指向外層的this,然后在內(nèi)層使用that表箭,就不會(huì)發(fā)生this指向的改變赁咙。
避免數(shù)組處理方法中的this
數(shù)組的map和foreach方法,允許提供一個(gè)函數(shù)作為參數(shù)燃逻。這個(gè)函數(shù)內(nèi)部不應(yīng)該使用this序目。
var o = {
v: 'hello',
p: [ 'a1', 'a2' ],
f: function f() {
this.p.forEach(function (item) {
console.log(this.v + ' ' + item);
});
}
}
o.f()
// undefined a1
// undefined a2
上面代碼相當(dāng)于
var temp = function(){
o.p.forEach(function (item) {
console.log(this.v + ' ' + item);
});
} //this指向全局變量
var o = {
v: 'hello',
p: [ 'a1', 'a2' ],
f: temp()
}
o.f()
// undefined a1
// undefined a2
我們同樣可以這樣修改
var o = {
v: 'hello',
p: [ 'a1', 'a2' ],
f: function f() {
var that = this;
this.p.forEach(function (item) {
console.log(that.v+' '+item);
});
}
}
o.f()
// hello a1
// hello a2
或者將this當(dāng)作foreach方法的第二個(gè)參數(shù),固定它的運(yùn)行環(huán)境伯襟。
var o = {
v: 'hello',
p: [ 'a1', 'a2' ],
f: function f() {
this.p.forEach(function (item) {
console.log(this.v + ' ' + item);
}, this);
}
}
o.f()
// hello a1
// hello a2
bind方法
bind方法用于將函數(shù)體內(nèi)的this綁定到某個(gè)對(duì)象猿涨,然后返回一個(gè)新函數(shù)。
var counter = {
count: 0,
inc: function () {
this.count++;
}
};
var func = counter.inc;
func();
counter.count // 0
count // NaN
上面代碼中姆怪,函數(shù)func是在全局環(huán)境中運(yùn)行的叛赚,這時(shí)inc內(nèi)部的this指向頂層對(duì)象window,所以counter.count是不會(huì)變的稽揭,反而創(chuàng)建了一個(gè)全局變量count俺附。因?yàn)閣indow.count原來等于undefined,進(jìn)行遞增運(yùn)算后undefined++就等于NaN溪掀。
var func = counter.inc.bind(counter);
func();
counter.count
//1
使用bind方法將inc方法綁定到counter以后事镣,再運(yùn)行func就會(huì)得到正確結(jié)果。
小結(jié)
對(duì)于this揪胃,我們只要記得其本質(zhì)就是call函數(shù)時(shí)傳入的第一個(gè)參數(shù)璃哟,如果函數(shù)調(diào)用形式不是 call 形式,請(qǐng)將其轉(zhuǎn)換為 call 形式喊递,函數(shù)的this值可以用call改變随闪,也可以用bind改變默認(rèn)的this值。