JavaScript中的This

由于this的运行期绑定的特性,它可以是全局对象,当前对象或者任意对象,这完全取决于函数的调用方式。

函数是否被new操作符调用

Javascript中没有类的概念,相应的,它的构造函数的概念也十分的特别。如果没有用new操作符调用,就和普通函数一样,如果有了new,就变成了一个构造函数。作为一个约定俗成的写法,构造函数以大写字母开头。

1
2
3
4
5
 function Point(x, y){ 
this.x = x;
this.y = y;
}
var point = new Point(0,0);

如果是一个构造函数,this绑定到新构造出来的函数中。也就是说上面这段代码会生成一个对象,将this绑定到这个对象上,函数执行结束之后返回这个对象。

函数是否通过apply和call调用

在Javascript中函数也是对象,是一种特殊的对象。那么函数也有属性也有方法,最著名的属性是prototype,最著名的方法是applycall。apply和call的区别是如果知道传入函数的参数就使用call,如果不确定参数,使用的是arguments数组传参,那么就用apply。

1
2
3
4
5
6
7
8
9
10
11
12
13
function Point(x, y){ 
this.x = x;
this.y = y;
this.moveTo = function(x, y){
this.x = x;
this.y = y;
}
}

var p1 = new Point(0, 0);
var p2 = {x: 0, y: 0};
p1.moveTo(1, 1);
p1.moveTo.apply(p2, [10, 10]);

首先利用构造函数生成一个对象p1,该对象具有moveTo方法。利用对象字面量的方法生成另外一个对象p2。调用p1.moveTo的apply(通过数组传递参数)方法,将运行时这个函数的this绑定到apply中的第一个参数也就是p2对象上。

总结一下,利用apply和call方法,就是将调用这个方法的函数运行时的this绑定到第一个参数。在例子中,就是将this.moveTo方法的this绑定到p2对象中。

函数是否有对象上下文

通俗的说就是这个函数是不是对象调用的,比方说上面那个例子中的p1.moveTo(1,1),这个moveTo方法就是p1对象调用的,等价于p1.moveTo(p1,[1,1])。 如果函数调用有对象上下文,this绑定到这个对象。

1
2
3
4
5
6
7
8
9
10
var point = { 
x : 0,
y : 0,
moveTo : function(x, y) {
this.x = this.x + x;
this.y = this.y + y;
}
};

point.moveTo(1, 1)//this 绑定到当前对象,即 point 对象

上面这个例子就是将函数里面的this绑定到调用的对象上。

如果上面这些都没有

如果函数执行的时候没有new,也不是通过apply和call调用的,前面也没有对象,那么this就是绑定到window当中。据说这个设计是毫无用处的,不管在什么情况下,我们都不需要将this绑定到window,但是它就是这么设计的,记住它吧。

1
2
3
4
5
6
7
8
9
10
var point = { 
x : 0,
y : 0,
moveTo : function(x, y) {
this.x = this.x + x;
this.y = this.y + y;
}
};
move =point.moveTo(1, 1);
move(1,1); //我被绑定到window上了,会生成全局变量x,y

总结

this的绑定就上面这四种情况,分析起来还是不难的吧?在新的ES6标准中fat arrow也会涉及到this的绑定。