关于this
this是javascript中的一个关键字,就是一个指针,指向我们调用函数的对象。
this是基于函数运行时的执行环境绑定的,也就是说this是动态绑定的。
执行环境可以看做是执行上下文,它包含了:
变量作用域(和作用域链条,闭包里面来自外部作用域的变量),函数参数,以及 this 对象的值。
this的指向
this总是指向它的直接调用者
function foo() {
console.log(this.a);
}
var a = 'apple';
foo(); // 'apple' => window
var a = '123';
var b = {
a: '456',
doo:function() {
console.log(this.a);
}
};
b.doo(); // '456' => b
var a = '123';
var b = {
a: '456',
c:{
a: '789',
doo:function() {
console.log(this.a);
}
}
};
b.c.doo(); // '789' => c (this指向上一级的对象)
var a = '123';
var b = {
a: '456',
doo: function () {
console.log(this.a);
}
};
var c = {
a: '789'
};
var t = b.doo;
c.doo = b.doo;
t(); // '123' => window (被赋值后,b不是直接调用者)
c.doo(); // '789' => c
var a = '123';
var b = {
a: '456',
doo: function () {
function woo() {
console.log(this.a);
}
woo();
}
};
b.doo(); // '123' => window (函数内定义函数,相当于函数调用,指向window)
apply、call和bind改变函数的 this 指向到指定的对象
bind可以覆盖apply和call
function foo() {
console.log(this.a);
}
var a = 1;
foo.apply({ a: 2 }); // 2
foo.call({ a: 2 }); // 2
foo.bind({ a: 2 })(); // 2
new 绑定
new一个函数时,会自动把this绑定在新对象上,并且会覆盖bind的绑定。以下是创建new的会执行的操作:
-
创建一个全新的对象。
var person = {};
-
这个新对象会被执行[[Prototype]]连接。新对象的_proto_属性指向构造函数的原型对象。
obj.__ proto __ = Person.prototype;
-
这个新对象会绑定到函数调用的 this。
var result = Person.call(obj);
-
判断返回值类型,如果是引用类型,就返回这个引用类型的对象。如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。
return typeof result === 'object' ? result : obj;
function foo1() {
this.a = 1;
}
function foo2() {
this.a = 2;
return {
a: 3
};
}
var a = new foo1();
var b = new foo2();
console.log(a); // {a: 1}
console.log(b); // {a: 3}
function showThis () {
console.log(this)
}
showThis() // window
new showThis() // showThis
var boss1 = { name: 'boss1' }
var boss1showThis = showThis.bind(boss1)
boss1showThis() // boss1
new boss1showThis() // showThis
优先级
new > call、apply、bind > 对象调用
箭头函数中的this
箭头函数没有this,通过查找作用域链来决定其值。this绑定的是最近一层非箭头函数的this,否则this的值则被设置为全局对象。
var a = '123';
var b = {
a: '456',
doo: () => {
console.log(this.a);
}
};
b.doo(); // '123' => b
setTimeout和setInterval中的this
这两个方法是挂在window对象下的。《JavaScript高级程序设计》第二版中,写到:“超时调用的代码都是在全局作用域中执行的,因此函数中this的值在非严格模式下指向window对象,在严格模式下是undefined”,所以第一个参数的this指向window。可以使用箭头函数自动绑定this。
var a = '123';
var b = {
a: '456',
foo: function() {
setTimeout(function(){
console.log(this.a)
}, 1)
},
hoo: function(){
setTimeout(() => {
console.log(this.a)
}, 1)
}
};
b.foo(); // '123'
b.hoo(); // '456'
闭包中的this
var a = '123';
var b = {
a: '456',
c: function() {
return function() {
return this.a
}
}
};
b.c()(); // '123'
闭包返回的函数不属于对象的一个方法,执行这个闭包相当于全局调用这个函数,所以this指向window。