什么是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值。