比起Java, C#等面向对象语言,this关键字在JS中有更多需要注意和理解的地方,下面就来一一看下几个场景的用法:
1. 跟 Java, C#等语言一样,this可以声明在构造函数里,用来定义成员变量
function foo(a) {
this.a = a;
}
var bar = new foo( 2 );
console.log( bar.a ); // 2
2. 如果不是作为new 的构造函数, this代表的是当前上下文的对象
function foo(num) {
console.log( "foo: " + num );
this.count++;
}
foo.count = 0;
var i;
for (i=0; i<10; i++) {
if (i > 5) {
foo( i );
}
}
// foo: 6
// foo: 7
// foo: 8
// foo: 9
console.log( foo.count ); // 0
上面的代码,foo.count 和this.count 不是一个变量, 在默认模式下,this.count创建了一个全局的变量,由于没有初始化,在++后变成NaN。 而在strict mode下, this.count会在运行时直接抛出undefined的错误
3. 隐式改变this
function foo() {
console.log( this.a );
}
var obj2 = {
a: 42,
foo: foo
};
var obj1 = {
a: 2,
obj2: obj2
};
obj1.obj2.foo(); // 42
this是当前上下文的对象,所以在obj1.obj2.foo()中,this指向的是obj2,所以this.a=obj2.a
4. 显式改变this
可以使用call, apply和bind三个方法来显示改变this
function foo() {
console.log( this.a );
}
var obj = {
a: 2
};
foo.call( obj ); // 2 obj并没有foo方法,使用foo.call把foo的强制绑定到obj的上下文
function foo(something) {
console.log( this.a, something );
return this.a + something;
}
var obj = {
a: 2
};
var bar = function() {
return foo.apply( obj, arguments ); //带参数的强制硬性绑定,无论调用环境如何,都会使用 obj 作为调用上下文
};
var b = bar( 3 ); // 2 3
//也可以用bind返回重新绑定过的函数,已供后面使用
function foo(something) {
console.log( this.a, something );
return this.a + something;
}
var obj = {
a: 2
};
var bar = foo.bind( obj );
var b = bar( 3 ); // 2 3
console.log( b ); // 5
function foo(el) {
console.log( el, this.id );
}
var obj = {
id: "awesome"
};
// use `obj` as `this` for `foo(..)
call和apply的区别仅仅是apply支持传递参数
《你所不知道的JS》对this做了很好的总结,优先级如下:
1. 如果是用new创建的this,就是新对象的成员函数: var bar = new foo()
2. 如果使用了call, apply或bind, 则为显式绑定,this指向call, apply或bind方法的第一个参数: var bar = foo.call(obj2 )
3. 隐式绑定: var bar = obj1.foo()
4. 默认的绑定,在strict模式下抛出undefined, 在普通模式下会生成全局变量: var bar = foo()
好了,规则都说完了,下面这段代码如果搞明白了,说明对this 的理解也过关了:
function foo(something) {
this.a = something;
}
var obj1 = {
foo: foo
};
var a = 4;
var obj2 = {};
obj1.foo(2);
console.log(obj1.a);
foo(5);
console.log(a);
obj1.foo.call(obj2, 3);
console.log(obj2.a);
var bar = new obj1.foo(4);
console.log(obj1.a);
console.log(bar.a);
原文: https://github.com/getify/You-Dont-Know-JS/blob/master/this%20%26%20object%20prototypes/ch1.md