this的绑定规则
this是在运行时进行绑定的,它的上下文取决于函数调用时的各种条件。this的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式。
当一个函数被调用时,会创建一个活动记录(执行上下文),这个记录会包含函数在哪里被调用(调用栈)、函数的调用方法、传入的参数等信息。this就是记录其中的一个属性,会在函数执行的过程中用到。
绑定规则
1. 默认绑定
最常用的函数调用类型:独立函数调用。
function foo(){
console.log(this.a);
}
var a=2;
foo();
this.a被解析成了全局变量a,因为函数调用应用了this的默认绑定,因此this指向全局变量。在这里,foo()直接使用了不带任何修饰符的函数引用进行调用,因此看出foo()只能使用默认绑定,无法应用其他规则。
如果使用严格模式,那么全局对象无法使用默认绑定,this会被绑定到undefined。严格模式下与foo()的调用位置无关。
2. 隐式绑定
考虑规则:调用位置是否有上下文,或者说是被某个对象包含。
function foo(){
console.log(this.a);
}
var obj={
a:2,
foo:foo
};
obj.foo();
当foo()被调用时,它的落脚点指向了obj对象。当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象,因为调用foo时this绑定到obj,因此this.a和obj.a是一样的。
对象属性引用链中只有最顶层会影响调用位置。
function foo(){
console.log(this.a);
}
var obj2={
a:42;
foo:foo
};
var obj1={
a:2,
obj2:obj2
};
obj1.obj2.foo();//42
隐式丢失:一个常见的this绑定问题就是被隐式绑定的函数会丢失绑定对象,也就是说会应用默认绑定,从而把this绑定到全局对象或者undefined上,取决于是否是严格模式。
function foo(){
console.log(this.a);
}
var obj={
a:2,
foo:foo
};
var bar=obj.foo;//函数别名
var a="oops,global";
bar();
虽然bar是obj.foo的一个引用,但是,它引用了foo函数本身,因此此时的bar实际是一个不带任何修饰的函数调用,因此应用了默认绑定。
function foo(){
console.log(this.a);
}
function doFoo(fn){
fn();
}
var obj={
a:2,
foo:foo
};
var a="oops,global";
doFoo(obj.foo);//oops,global
参数传递实际就是一种隐式赋值,因此我们传入函数时也会被隐式赋值。
隐式绑定时,我们必须在一个对象内部包含一个指向函数的属性,并通过这个属性间接引用函数,从而把this绑定到这个对象上。
window.id='window';
document.getElementById('div').onclick=function(){
alert(this.id);//div1
var callback=function(){
alert(this.id);//window
}
}
document.getElementById('div1').onclick=function(){
var that=this;
var callback=function(){
alert(that.id);//div1
}
callback();
}
3. 显示绑定
显示绑定可以解决丢失绑定的问题
1、硬绑定
function foo(){
console.log(this.a);
}
var obj={
a:2
};
var bar=function(){
foo.call(obj);
};
bar();//2
setTimeout(bar,100);//2
//硬绑定的bar不能再修改它的this
bar.call(window);//2
硬绑定的应用场景就是创建一个包裹函数,传入所有的参数并返回接收到的所有值。
2、API调用的“上下文”
function foo(el){
console.log(el,this.id);
}
var obj={
id:"awesome"
};
[1,2,3].forEach(foo,obj);
4. new绑定
使用new来调用函数,会自动执行以下操作
1、创建一个新对象
2、这个新对象会被执行原型连接
3、这个新对象会被绑定到函数调用的this
4、如果函数没有返回其他对象,那么new表达式的函数调用会自动返回这个新对象。
判断this
1、函数是否在new中调用,如果是的话this绑定的是新创建的对象
2、函数是否通过call、apply或者硬绑定调用,如果是的话,this绑定的是指定的对象
3、函数是否在某个上下文对象中调用(隐式绑定),如果是的话,this绑定的是那个上下文对象
4、如果都不是的话,使用默认绑定,严格模式下,绑定到undefined,否则绑定到全局对象。
this的四种使用场景
this要在执行时才能确认值,定义时无法确认。
var a={
name:'A',
fn:function(){
console.log(this.name)
}
}
a.fn() //this===a
a.fn.call({name:'B'})//this==={name:'B'}
var fn1=a.fn
fn1()//this===window
1、作为构造函数执行
function Foo(name){
this.name=name
}
var f=new Foo('zhangsan')
2、作为对象属性执行
var obj={
name:'A',
printName:function(){
console.log(this.name)
}
}
obj.printName()
3、作为普通函数执行
function fn(){
console.log(this)
}
fn()
4、call apply bind
function fn1(name){
alert(name);
console.log(this)
}
fn1.call({x:100},'zhangsan')
var fn2=function(name,age){
alert(name);
console.log(this);
}.bind({y:200})
fn2('zhangsan',20)
本文详细介绍了JavaScript中this关键字的绑定规则,包括默认绑定、隐式绑定、显示绑定及new绑定等四种主要规则,并通过实例解释了如何判断this的绑定情况。
1362

被折叠的 条评论
为什么被折叠?



