在js中,this的指向在函数定义的时候是确定不了的,在函数被调用的时候,才能确定this的指向。
下面通过例子来说明:
一、全局window中(默认绑定)
var a = 10;
function foo(){
console.log(this);
console.log(this.a);
}
foo(); // window 10
在这个例子里,在全局window中直接调用函数foo,this指向就是全局的window对象,所以可以获取a的值,但是如果加上严格模式,就不一样了
"use strict"
function foo(){
console.log(this);
}
foo(); // undefined
在严格模式下,全局window中调用函数foo时,this就不再是指向window对象,而是指向undefined,这时如果想获取this.a就会报错。
二、作为对象的方法(隐式绑定)
var a = 10
var obj = {
a: 20,
foo() {
console.log(this);
console.log(this.a);
}
}
obj.foo(); // obj 20
在这个例子中,函数foo作为对象obj的方法被调用,此时this的指向就是obj对象,thisa.a就是obj.a。这个对象的结构还比较简单,如果对象的结构更加复杂时呢?
var obj = {
a: 20,
c: 'ccc',
b: {
a: 30,
foo() {
console.log(this.a); // 30
console.log(this.c); // undefined
}
}
}
obj.b.foo();
可以看出,此时this.a的值时obj.b里面a的值,而不是obj中a的值,而this.c是undefined,说明了此时foo中this的指向是obj.b这个对象。
把上面例子再稍微变一下:
var obj = {
a: 20,
c: 'ccc',
b: {
a: 30,
foo() {
console.log(this.a);
}
}
}
var bar = obj.b.foo;
bar(); // undefined
只是把函数赋值给另一个变量,然后再调用这个函数类型的变量,结果就与上边完全不一样了。这是因为赋值操作只是把函数的地址给了bar,bar调用的时候还是在全局window之中,全局中没有a变量,所以就是undefined。
回调函数中:
var a = 10;
var obj = {
a: 20,
foo() {
setTimeout(function (){
console.log(this.a);
}, 1000);
}
}
obj.foo(); // 10
这个例子里的this.a不是obj.a,而是window.a,这个是由于foo里的回调函数导致的。表面上看起来是obj调用的函数,但是实际上回调函数在执行的时候,是在全局window环境中执行的,而不是在obj对象的环境中,所以这里的this指向的是window对象。
箭头函数中:
var a = 10;
var foo = () => {
console.log(this.a);
}
var obj = {
a : 20,
foo: foo
}
foo(); // 10
obj.foo(); // 10
箭头函数没有自己的this,它的this是继承而来的,它会向上层查找,把上层的this当做是自己的this。
var a = 10;
var obj = {
a: 20,
foo: () => {
console.log(this.a);
}
}
obj.foo(); // 10
普通的对象没有this,所以箭头函数作为函数的属性值时,this指向的是对象所在环境中的this,这里还是window。
三、call,apply(显示绑定)
function foo() {
console.log(this.a);
}
var a = 10;
var obj1 = {
a: 20,
};
var obj2 = {
a: 30,
};
foo.call(obj1); // 20
foo.apply(obj2); // 30
call和apply会修改函数中的this指向
四、构造函数中(new绑定)
function Person(){
this.a = 10
console.log(this);
}
var person = new Person();
console.log(person.a); // 10
在构造函数中,this的指向就是new出来的实例对象,所以这里的person.a等于构造函数里的this.a,但是遇到有返回值时,可能就有点不一样了:
function Person(){
this.a = 10
return 123;
}
var person = new Person();
console.log(person.a); // 10
function Person(){
this.a = 10
return {
a: 20
}
}
var person = new Person();
console.log(person.a); // 20
当构造函数的返回值是基本数据类型时,this还是指向实例对象,当返回值是引用数据类型时,this指向的就是返回值了。
五、this绑定的优先级
- new绑定
- 显示绑定
- 隐式绑定
- 默认绑定
回调函数和箭头函数中的this指向和隐式绑定的不一样,这个就做隐式丢失。