什么是this
this是JS中一個非常重要的關鍵字。this 就是你 call 一個函數時,傳入的 context。任何形式的函數調用都可以寫成call形式,傳入的第一個參數就是this。
f(a,b) 等價于 f.call(undefined , a , b)
f.m.n(a,b) 等價于 f.m.n.call(f.m , a , b)
fn.call(context , p1 , p2)
所以當我們無法確定this時我們可以轉換成call形式來確認this。
如何確定this
通常我們確定this會用以下方式
1、console.log(this)
2、查看API源代碼
3、查看API相關文檔
this的使用
全局變量
function f() {
console.log(this); // window
}
var a=1
function f() {
console.log(this.a);
}
f()
//1
對象的方法
當A對象的方法被賦予B對象,該方法中的this就從指向A對象變成了指向B對象。所以要特別小心,將某個對象的方法賦值給另一個對象,會改變this的指向。
var obj ={
foo: function () {
console.log(this);
}
};
obj.foo() // obj
但是,只有這一種用法(直接在obj對象上調用foo方法),this指向obj;其他用法時,this都指向代碼塊當前所在對象(瀏覽器為window對象)。
(obj.foo = obj.foo)()
/ 等價于 /
(obj.foo = function () {
console.log(this);
})()
//window
可以這樣理解,obj和obj.foo儲存在兩個內存地址,簡稱為M1和M2。只有obj.foo()這樣調用時,是從M1調用M2,因此this指向obj。但是,上面情況是直接取出M2進行運算,然后就在全局環境執行運算結果(還是M2),因此this指向全局環境。
避免多層this
由于this的指向是不確定的,所以切勿在函數中包含多層的this。
var o = {
f1: function () {
console.log(this);
var f2 = function () {
console.log(this);
}();
}
}
o.f1()
// Object
// Window
上面代碼等價于
var temp = function () {
console.log(this);
};
var o = {
f1: function () {
console.log(this);
var f2 = temp();
}
}
當我們把代碼修改為
var o = {
f1: function() {
console.log(this);
var that = this;
var f2 = function() {
console.log(that);
}();
}
}
o.f1()
// Object
// Object
上面代碼定義了變量that,固定指向外層的this,然后在內層使用that,就不會發生this指向的改變。
避免數組處理方法中的this
數組的map和foreach方法,允許提供一個函數作為參數。這個函數內部不應該使用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
上面代碼相當于
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當作foreach方法的第二個參數,固定它的運行環境。
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方法用于將函數體內的this綁定到某個對象,然后返回一個新函數。
var counter = {
count: 0,
inc: function () {
this.count++;
}
};
var func = counter.inc;
func();
counter.count // 0
count // NaN
上面代碼中,函數func是在全局環境中運行的,這時inc內部的this指向頂層對象window,所以counter.count是不會變的,反而創建了一個全局變量count。因為window.count原來等于undefined,進行遞增運算后undefined++就等于NaN。
var func = counter.inc.bind(counter);
func();
counter.count
//1
使用bind方法將inc方法綁定到counter以后,再運行func就會得到正確結果。
小結
對于this,我們只要記得其本質就是call函數時傳入的第一個參數,如果函數調用形式不是 call 形式,請將其轉換為 call 形式,函數的this值可以用call改變,也可以用bind改變默認的this值。