this关键字
分析如下代码,执行同一函数,输出结果是什么?
var obj = {
name: 'default-obj',
show: function() {
console.info('this name is ' + this.name);
}
};
obj.show.apply(window);
obj.show.call(this);
obj.show();
setTimeout( obj.show ,100 );
this实际上是在函数被调用时发生的绑定关系,它指向什么完全取决于函数在哪里被调用?
this绑定规则
默认绑定
function show() {
console.info(this.a);
}
var a = 'window-value';
show(); // window-value
在非严格模式下,无法应用其他绑定规则的情况下啊,this默认绑定为window
隐式绑定
调用位置是否有上下文对象
function foo() {
console.info(this.name);
}
var obj = {
name : 'obj-name',
show: foo
};
var name = 'window-name';
obj.show(); //obj-name
当函数引 用有上下文对象时,隐式绑定规则会把函数调用中的 this 绑定到这个上下文对象
注意如下情况会丢失this绑定
- 函数指向的是一个引用
function foo() {
console.info(this.name);
}
var obj = {
name : 'obj-name',
show: foo
};
var name = 'window-name';
var show = obj.show;
show();
- 回调函数引用传递
function foo() {
console.info(this.name);
}
var obj = {
name : 'obj-name',
show: foo
};
function handler(error) {
error();
}
var name = 'window-name';
handler(obj.show);
显式绑定
通常通过以下两种方法来显式修改绑定的对象
function foo() {
console.info(this.name);
}
var obj = {
name : 'obj-name',
show: foo
};
var name = 'window-name';
obj.show.call(obj);
foo.apply(obj);
- 那么call与apply的异同是什么呢?
- 功能相同
- 接收参数不一样 call( obj, [arg1...] ); apply(obj , arg1, arg2 ...);
硬绑定
ES5后函数的原型中添加了一个bind方法,可以给函数硬绑定一个对象, 返回绑定后的新函数
function foo() {
console.info(this.name);
}
var obj = {
name : 'obj-name',
show: foo
};
var newfoo = foo.bind(obj);
var name = 'window-name';
setTimeout(newfoo, 100);
newfoo();
new 绑定
new 创建对象的过程
- 创建(或者说构造)一个全新的对象。
- 这个新对象会被执行 [[ 原型 ]] 连接。
- 这个新对象会绑定到函数调用的 this。
- 如果函数没有返回其他对象,那么 new 表达式中的函数调用会自动返回这个新对象。
判断this
现在我们可以根据优先级来判断函数在某个调用位置应用的是哪条规则。可以按照下面的 顺序来进行判断:
- 函数是否在 new 中调用(new 绑定)?如果是的话 this 绑定的是新创建的对象。 var bar = new foo()
- 函数是否通过 call、apply(显式绑定)或者硬绑定调用?如果是的话,this 绑定的是 指定的对象。 var bar = foo.call(obj2)
- 函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this 绑定的是那个上 下文对象。 var bar = obj1.foo()
- 如果都不是的话,使用默认绑定。如果在严格模式下,就绑定到 undefined,否则绑定到 全局对象。 var bar = foo() 就是这样。
对于正常的函数调用来说,理解了这些知识你就可以明白 this 的绑定原理了。 不过……凡事总有例外