浅谈JavaScript中this的指向更改
JS中this指向的更改
JavaScript中this的指向问题前面已经总结过,但在实际开中,很多场景都需要改变this的指向。现在我们讨论更改this指向的问题。
call更改this指向
call的使用语法:func.call(thisArg,arg1,arg2,...)
call方法需要一个指定的this值(this要指向的对象)和一个或者多个参数。提供的this值会更改调用函数内部的this指向。
//使用call方法改变调用函数执行上下文的this指向
varanimal='小猫';
vartimes='15小时';
functiongreet(){
letstr=this.animal+'睡觉时间一般为:'+this.times;
console.log(str);
}
vardogObj={
animal:'小狗',
times:'8小时'
};
varpigObj={
animal:'小猪',
times:'13小时'
}
greet();//小猫睡觉时间一般为:15小时
greet.call(dogObj);//小狗睡觉时间一般为:8小时
greet.call(pigObj);//小猪睡觉时间一般为:13小时
greet.call();//小猫睡觉时间一般为:15小时
当直接调用函数greet时,函数greet内部的this指向的是全局对象Window。
函数greet调用call()方法并传递对象dogObj时,函数greet内部的this就指向了对象dogObj。
函数greet调用call()方法并传递对象pigObj时,函数greet内部的this就指向了对象pigObj。
call()不传参的话,在严格模式下,this的值将会是undefined;否则将会指向全局对象Window。
匿名函数调用call方法:
varbooks=[{
name:'CSS选择器',
price:23
},{
name:'CSS世界',
price:35
},{
name:'JavaScript语言设计',
price:55
}];
for(vari=0;i
call实现继承:
//实现两个数相加的构造函数
functionCalcA(){
this.add=function(a,b){
returna+b;
}
}
//实现两个数相减的构造函数
functionCalcS(){
this.sub=function(a,b){
returna-b;
}
}
//计算构造函数
functionCalc(){
console.log(this);//Calc{}
CalcA.call(this);
CalcS.call(this);
console.log(this);//Calc{add:ƒ,sub:ƒ}
}
varcalc=newCalc();
console.log(calc.add(2,3));//5
console.log(calc.sub(10,1));//9
构造函数Calc通过call方法使构造函数CalcA、CalcS中的this指向了Calc自己,从而继承了它们的属性及方法。所以,构造函数Calc生成的实例对象也能够访问构造函数CalcA、CalcS中的属性及方法。
apply方法更改this指向
apply的使用语法:func.apply(thisArg,[argsArray])
apply的用法与call方法类似,只不过call方法接受的是参数列表,而apply方法接受的是一个数组或者类数组对象。上面的例子完全可以将call更换为apply,只不过apply方法只能接受两个参数,而且第二个参数是一个数组或者类数组对象。
bind方法更改this指向
bind的使用语法:func.bind(thisArg,arg1,arg2,...)
bind的参数与call相同,但是bind返回的是一个改变this指向后的函数实例。
varpetalNum=100;
functionFlower(){
this.petalNum=Math.ceil(Math.random()*10)+1;
}
Flower.prototype.declare=function(){
console.log(this);
console.log('thisisabeautifulflowerwith'+this.petalNum+'petals');
}
Flower.prototype.bloom=function(){
console.log(this);//Flower{petalNum:7}
//如果不绑定this就会指向Window全局对象
window.setTimeout(this.declare,1000);
//bind绑定this,指向Flower的原型对象
window.setTimeout(this.declare.bind(this),2000);
}
varflower=newFlower();
flower.bloom();
实例对象flower调用bloom方法后,bloom内的this指向构造函数的原型对象。
1秒后延迟函数调用构造函数的declare方法,此时执行函数declare中的this指向Window。打印的结果如下:
//Window{parent:Window,postMessage:ƒ,blur:ƒ,focus:ƒ,close:ƒ,…}
//thisisabeautifulflowerwith100petals
2秒后延迟函数调用构造函数的declare方法,此时执行函数declare通过bind将this(构造函数的原型对象)绑定。打印的结果如下:
//注意,此时petalNum的值时随机取的。
//Flower{petalNum:7}
//thisisabeautifulflowerwith7petals
这里将bind换成call,apply会导致立即执行,延迟效果会失效。
ES6的箭头函数更改this指向
箭头函数中的this是在定义函数的时候绑定,而不是在执行函数的时候绑定。所谓定义时候绑定,就是指this是继承自父执行上下文的this。
vara=1;
varobj={
a:2,
f1:function(){
console.log(this.a)
},
f2:()=>{
console.log(this.a)
}
}
obj.f1();//2
obj.f2();//1
obj.f1()执行后打印的是2,这里好理解,obj调用f1函数,那么函数中的this就指向调用对象obj。可以看出,这里this是在执行函数的时候绑定的。
obj.f2()执行后打印的是1。f2是箭头函数,那么函数中的this是继承自父执行上下文的this。这里箭头函数的父级是对象obj,obj的执行上下文就是全局对象Window,那么箭头函数中的this就指向了全局对象了。
再看一个例子:
vara=11;
functiontest(){
this.a=22;
letb=()=>{console.log(this.a)}
b();
}
test();//22
按着定义的理解,应该打印出11才对呀,因为箭头函数父级的执行上下文就是Window全局对象,此时打印的是全局对象的a。
先不要着急,先慢慢分析,上面的分析是对的,箭头函数的this就是指向Window对象。test函数在全局环境下调用时其内部的this就指向了全局Window对象,代码中的this.a=22;就将全局中的a重新赋值了,所以箭头函数在全局对象中找到的a值就是22。我们可以在控制台上输入window.a查看全局对象中的a值,结果打印22,所以我们就不难理解箭头函数中打印的结果为什么是22了。如果将代码中的this.a=22;修改为vara=22;,那么箭头函数中打印的结果就是11了。
箭头函数会继承外层函数调用的this绑定,这和varself=this;的绑定机制一样。箭头函数中,this指向固定化,箭头函数根本就没有自己的this,所以也就不能用作构造函数使用了。
到此这篇关于浅谈JavaScript中this的指向更改的文章就介绍到这了,更多相关JavaScript中this指向更改内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!