- 关于JS中THIS的处理情况汇总
(1)给当前元素的某个事件行为绑定方法,当事件行为触发,方法被执行,方法中的this一般都是当前操作的元素。排除:IE6~8中,基于attachEvent进行的DOM2事件绑定,方法中的this是window
document.body.onclick=function (){
console.log(this); //body
};
document.body.addEventListener('click',function(){
console.log(this); //body
});
(2)函数执行,看函数前面是否有”点“,有”点“,”点“前面是谁this就是谁,没有"点”,this是window。JS严格模式下,没有“点”,this是undefined;匿名函数(自执行函数/回调函数)一般this是window/undefined;括号表达式中有特殊的处理。
const fn=function (){
consoel.log(this);
};
let obj={
name:'obj',
fn:fn
};
fn(); //window
obj.fn(); //obj
(obj.fn)(); //this->obj
//括号表达式中有多项,也只取最后一项;但是this是window,而不是之前的obj
(10,20,obj.fn)(); //this->window
(function (){
console.log(this); //window
})();
[1,2].sort(function (a,b){
console.log(this); //window
});
[1].forEach(function (item,index){
//forEach内部做了特殊的处理,传递的第二个参数是为了改变回调函数中的this指向的
console.log(this); //obj
},obj);
(3)构造函数执行“new xxx",函数体中的this 是当前类的实例
function Fn(){
this.x=10;
}
Fn.prototype.sum=function (){};
Fn(); //window
let f=new Fn(); //this->f
f.sum(); //this->f
f.__proto__.sum(); //this->f.__proto__
(4)ES6中的箭头函数(或者基于{}形成的块级上下文)里面没有this,如果代码中遇到this也不是自己的,而是它所在上下文中的this.
let obj={
name:'obj',
fn(){
//this->obj
//1s后执行函数,把obj.name改为lly
let that=this;
setTimeout(function(){
//that存储的是上级上下文中的this
that.name='lly';
},1000);
//简单的方法:使用箭头函数
setTimeout(()=>{
//this->用的是上级上下文中的this,也就是obj.
this.name='lly';
},1000);
}
};
obj.fn();
(5)可以基于Function.prototype上的call/apply/bind方法强制改变函数中的this指向,对箭头函数没有效果,因为其不存在this.
call方法
<script>
const fn=function(x,y){
this.total=x+y;
console.log(this);
}
let obj={
name:'lly'
}
fn(); //this->window
obj.fn(); //报错:obj.fn is not a function
//call方法
//函数.call([context],params1,params2,...)
//简单:把函数执行,让函数中的this指向[context],并且把params1/params2...作为实参传递给函数
//详细说明:
//首先fn基于原型链__proto__,找到Function.prototype.call方法,并且把call方法执行
//call方法中的this就是当前操作的实例fn,传递给call方法的第一个实参是未来改变fn中的this指向,剩余的实参,都是未来要依次传递给fn的参数信息
//call方法执行的过程中,实现了这样的处理:把fn【call中的this】执行,让fn中的this指向[context],并且把params1,params2...作为实参传递给fn,以此达到最后的效果
//最后接收fn执行的返回结果,作为返回值返给外部
let res=fn.call(obj,10,20);
fn.call(10,20); //this->10 x=10 y=undefined
fn.call(); //fn:this->window 第一个参数不传或者传递的是null/undefined,在JS非严格模式下,最后fn中的this都是window(严格模式下,不传this是undefined,传递null/undefined,this也会改为对应的值)
</script>
apply方法
函数.apply([context],[params1,params2,…])
call和apply的唯一区别:执行函数的时候,需要传递给函数的参数信息,在最开始传递给call/apply的时候,形式不一样。
call是需要把参数一个个传递给call,call方法内部再一个个传递给函数
apply是需要把参数放在一个数组中传递给apply,但是apply内部也会帮我们把接受数组中的每一项一项项的传递给函数
fn.apply(obj,[10,20]);
bind方法
call/apply在执行的时候,都会立即把要操作的函数执行,并且改变它的this指向
bind是预处理:执行bind只是预先把函数中需要改变的this等信息存储起来(预设好),但是此时函数并不会被执行,执行bind会返回一个匿名函数,当后期执行匿名函数的时候,再去把之前需要执行的函数执行,并且改变this为预设的值。
需求:1s后执行,并且让fn中的this变为obj,传递10,20
setTimeout(fn,1000); //1s后执行fn,但是this->window,x/y都是undefined
setTimeout(fn.call(obj,10,20),1000); //这样也不可以,因为在设置定时器的时候,基于call方法,就把fn已经执行了,虽然this和参数都可,但是并不是在1s后执行的。把fn执行的返回结果绑定给定时器,1s后执行的是返回结果。
setTimeout(function(){ fn.call(obj,10,20) },1000); //这样可以
setTimeout(fn.bind(obj,10,20),1000); //可以