前端this指向性问题

 

时间久了,对前端this的指向中某些细节有些遗忘,单独拿出来整理一下,主要有以下几个部分

  • 默认绑定,隐式绑定,显式绑定
  • 构造函数
  • 箭头函数(情况多,且相对复杂)
  • map()等api中回调函数的this
  • 为什么某些情况使用变量重新定义this

1.默认绑定、隐式绑定、显式绑定

首先先来说说各种绑定方式之前的区别

默认绑定:

默认绑定也就是普通函数中this的绑定方式,this的指向是window

function test(){
    console.log(this);
}

test()   //window

隐式绑定:

最典型的就是对象中的某个属性是方法,这种this的指向就一句话:谁调用,this就指向谁!

var obj = {
    name:'Tom',
    color:['red','green','blue','yellow'],
    test:function(){
        console.log(this);    
    }
}

obj.test()  //this指向obj(也就是当前的对象)
//多说一句,如上例,obj调用了这个test方法,在执行过程中,词法环境(执行上下文)确定了this的指向

显式绑定:

三种方式call(),apply()和bind(),这几种方式是强行改变this的指向。将改变后的指向当做第一个函数的参数传入,举个栗子

var obj = {
    name:'Tom',
    color:['red','green','blue','yellow'],
    test:function(height,weight){
        console.log(this);
        console.log(height);
        console.log(weight);    
    }
}

var db = {
    name:'Jerry',
}

//this全部指向db
obj.test.call(db,'180cm','60kg');
obj.test.apply(db,['180cm','60kg']);
obj.test.bind(db,'180cm','60kg')();

顺便区分一下这三个方法

call():所有参数逐个列出来

apply():所有参数放到一个数组中

bind():参数形式和call()相同,相较于前两者,返回的是一个函数,需要再次执行,所以会是bind()() 

2.构造函数

执行构造函数会创建一个新的对象,this指向这个新的对象

function Test(){
    this.name='Tom';
    console.log(this);
}

var res=new Test();
console.log(res.name)  //Tom

3.箭头函数(情况多,且相对复杂)

大家都知道箭头函数没有自己的this,要向外部找,但是箭头函数的使用太广泛了,到处都有他的影子。回调,对象,普通函数,情况一多就容易发生混淆。一点一点梳理

1.首先箭头函数的this定义:箭头函数的this是在定义函数时绑定的,不是在执行过程中绑定的。也就是说,箭头函数在定义的时候this就已经确定了。

2.箭头函数指向外部的this,如果外部是在全局环境中,那箭头函数指向window。

3.正是因为箭头函数没有自己的this,所以也不可以当做构造函数也不能使用call(),apply()和bind()。

4.如果箭头函数被非箭头函数包含,则this绑定指向的是最近一层非箭头函数的this;否则,this的值会被设置为全局对象

全局环境下回调函数:

/*全局环境中,这里是setTimeout()和map()的回调函数,这一类型的统统指向window,像forEach(),every()*/

//箭头函数的this指向window
setTimeout(()=>{
    console.log(this)
},1000)

//箭头函数的this指向window
var arr=[1,2,3];
var arrCopy=arr.map((item)=>{
    console.log(this);
    return item;
})

 对象中的某个属性为箭头函数:

var obj={
    name:'Tom',
    func:()=>{
        console.log(this)
    }
}

obj.func();

全局环境下普通函数返回箭头函数:

function test(){
    var name='Tom';
    console.log(this);
    return ()=>{
        console.log(this);
    }
}

test()();  //两次的输出都为window
/*
    理解:
    第一个输出为window好理解,就是普通函数this指向window
    第二个输出为window是因为箭头函数被普通函数包含,this绑定指向的是最近一层非箭头函数的this
    在这个例子最近一层非箭头函数就是test(),而test()的this指向就是window,所以该箭头函数的this也是
    window
*/

对象中的某个属性为函数,该函数返回箭头函数:

var obj={
    name:'Tom',
    func:function(){
        console.log(this);
        return ()=>{
            console.log(this);
        }
    }
}

obj.func()();   //两次的this都指向obj

/*
    理解:
    第一个输出为obj是因为obj调用了func(),谁调用,this指向谁
    第二个输出为obj和上面的例子一样,尽管整体是个对象,但箭头函数依然被普通函数包含,this绑定指向的是最近一层非箭头函数的this
    这里最近一层非箭头函数是func(),由于obj的调用,func()的this指向obj,所以该箭头函数的this也是obj
    
*/

4.map()等api中回调函数的this

回调函数中的this默认是指向window的,因为本质上是在函数内callback,并没有.前的对象调用

全局环境下

//输出window
var arr=[1,2,3];
arr.forEach(function(item){
    console.log(this);
})

对象中

var obj={
    num:[1,2,3,4,5],
    func:function(){
        this.num.forEach(function(item){
            console.log(this);              
        })
    }
}

obj.func()  //输出window

5.为什么某些情况使用变量重新定义this

根本的原因在于有些情况想要的this拿不到。举个例子

 var username = "Tom";
 var obj = {
     username:"Jerry",
     getUserName(){  
         setTimeout(function(){
            // 这里的this指向window所以正常来说会的到  Tom
             console.log(this.username);
        })
    }
}
obj.getUserName(); // Tom

这里的getUserName()方法执行后输出的username为Tom,因为方法在回调函数中,this指向window是没有问题的,但是如果我的需求就是让setTimeout执行后输出的是Jerry,要怎么做呢?

1.显性绑定,bind()、apply()、call()随便用一个

2.箭头函数

箭头函数指向最近一层非箭头函数的this,就是这里的getUserName,obj调用的getUserName方法,this指向obj,所以最终的this.username为Jerry

 var username = "Tom";
 var obj = {
     username:"Jerry",
     getUserName(){  
         setTimeout(()=>{
             console.log(this.username);   // 这里的this指向obj
        })
    }
}
obj.getUserName(); // Jerry

3.变量重新定义this

使用一个变量newThis把getUserName的this存起来,再给回调函数使用。简单好用

 var username = "Tom";
 var obj = {
     username:"Jerry",
     getUserName(){  
         var newThis=this;
         setTimeout(function(){
            console.log(newThis.username);    //这里的newThis指向obj

         })
    }
}
obj.getUserName(); // Jerry

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值