JS中this的4种绑定规则详解
JS中this是什么
理解this之前,先纠正一个观点,this既不指向函数自身,也不指函数的词法作用域。
如果仅通过this的英文解释,太容易产生误导了。
它实际是在函数被调用时才发生的绑定,也就是说this具体指向什么,取决于你是怎么调用的函数。也就是说谁调用的this,this就指向谁
JS中this说明
ES6中的箭头函数采用的是词法作用域。
为什么要使用this:使API设计得更简洁且易于复用。
this即不指向自身,也不指向函数的词法作用域。
this的指向只取决于函数的调用方式
this绑定规则
new>显示绑定>隐式绑定>默认绑定
默认绑定
当独立函数调用时,不管是否在调用栈中,this都指向全局对象(浏览器中为window)
严格模式下,不能将全局对象用于默认绑定。
vara=2;
functionfoo(){
console.log(this.a);
}
functionbar(){
vara=5;
foo();
}
bar();//2
隐式绑定
当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。
对象属性引用链中只有最后一层在调用位置中起作用。
要求:对象内部必须包含一个指向函数的属性,该对象可通过这个属性间接引用函数。
functionfoo(){
console.log(this.a);
}
varobj2={
a:42,
foo:foo
};
varobj1={
a:2,
obj2:obj2
};
obj1.obj2.foo();//42
隐式丢失
functionfoo(){
console.log(this.a);
}
varobj={
a:2,
foo:foo
};
varbar=obj.foo;//这里bar将引用foo函数本身,所以不带有函数对象的上下文
vara="oops,global";//a是全局对象的属性
bar();//"oops,global"
和回调函数的情况下(参数传递时的隐式赋值)
functionfoo(){
console.log(this.a);
}
functiondoFoo(fn){
//参数传递时,相当于fn=obj.foo,就和上个例子一样了
fn();//<--call-site!
}
varobj={
a:2,
foo:foo
};
vara="oops,global";//`a`alsopropertyonglobalobject
doFoo(obj.foo);//"oops,global"
显式绑定
采用call()和apply(),通过传入一个对象(若为基本类型,会被封装函数转为对象—装箱),将this绑定到该对象。
硬绑定
functionfoo(){
console.log(this.a);
}
varobj={
a:2
};
varbar=function(){
foo.call(obj);
};
bar();//2
setTimeout(bar,100);//2
//硬绑定后bar无论怎么调用,都不会影响foo函数的this绑定
bar.call(window);//2
硬绑定的典型应用是如下的包裹函数:
functionfoo(something){
console.log(this.a,something);
returnthis.a+something;
}
varobj={
a:2
};
varbar=function(){
returnfoo.apply(obj,arguments);//将obj对象硬编码进去
};
varb=bar(3);//23
console.log(b);//5
即将内部函数用apply硬绑定到某个对象,无论怎么调用这个包裹函数,都不会影响内部函数的this。
bind辅助函数如下:
functionfoo(something){
console.log(this.a,something);
returnthis.a+something;
}
//simple`bind`helper
functionbind(fn,obj){
returnfunction(){
returnfn.apply(obj,arguments);//利用参数将obj传入进去
};
}
varobj={
a:2
};
varbar=bind(foo,obj);//bind(foo,obj)会返回一个包裹函数
varb=bar(3);//23
console.log(b);//5
总结:上述包裹函数,想要包裹其他函数,只能一个一个重复写,硬编码的方式导致不能被重用,当某种功能需要多次重复使用时,将其抽象出来,成为函数。
new绑定
任何函数都可能被用作构造函数,当函数被new操作符“构造调用”时,会执行下面操作:
1.创建一个新对象(若该函数不是JS内置的,则创建一个新的Object对象);
2.将this绑定到这个对象;
3.执行构造函数中的代码(为这个新对象添加属性);
4.若函数没有返回其他对象,则自动返回这个新对象;若函数有return返回的是非对象,则还是自动返回这个新对象,即覆盖那个非对象。
functionfoo(a){
this.a=a;
}
varbar=newfoo(2);
console.log(bar.a);//2
补充说明
间接引用
functionfoo(){
console.log(this.a);
}
vara=2;
varo={a:3,foo:foo};
varp={a:4};
o.foo();//3
(p.foo=o.foo)();//2,由于p.foo=o.foo的返回值是目标函数的引用,所以调用位置是foo(),而不是p.foo()或o.foo()
箭头函数:不使用这四个this规则,根据词法作用域来决定this。
functionfoo(){
//返回一个箭头函数
return(a)=>{
//`this`hereislexicallyadoptedfrom`foo()`
console.log(this.a);
};
}
varobj1={
a:2
};
varobj2={
a:3
};
//foo()不是箭头函数,他的this被绑定到obj1
varbar=foo.call(obj1);//foo.call(obj1)返回箭头函数,所以bar为箭头函数
bar.call(obj2);//2!箭头函数的this无法被修改,new也不行
如下为和箭头函数一样的模式:
functionfoo(){
varself=this;//lexicalcaptureof`this`
setTimeout(function(){
console.log(self.a);
},100);
}
varobj={
a:2
};
更多关于JS中this对象的相关文章大家可以点击下面的相关链接
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。