this指向问题、改变this的方法

1,739 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。详情

this的几种情况

this

this是存在于作用域对象中的一个关键字,this本身不是作用域。作用域只分为全局作用域和函数作用域。

判断this指向:一定不要看在哪里定义。一定只看将来在哪里,如何被调用。

1. obj.fun()

obj.fun()调用时,fun函数中的this指向obj对象

2. new

new一个构造函数,this指向new出来的新对象

3. 原型对象上方法中的this

构造函数.prototype.fun= function(){}时,fun函数中的this指向调用fun的子对象:谁调用指向谁

以上三种this在这篇文章中有详细讲解:# 浅谈javascript面向对象三大特点,通过面向对象看原型原型链

4. 直接调用

fun()匿名函数自调回调函数中的this指向window(严格模式(use strict)下,this指向undefined 因为这类函数调用时,前边即没有.,也没有new!)

5. DOM事件的处理函数

button.onclick=function(){}button.addEventListener(“click”,function(){…})之类的事件函数中的this,指向当前的DOM元素对象。

6. Vue中

vue的this默认指向当前Vue对象

```js
<button@click=”fun”>
export default{
    //vue中methods中的方法中的this默认都指当前vue组件对象
    methods:{
        fun(e){ e.target }
        //如果想获得当前出发事件的DOM元素对象,必须用$event关键字和e.target联合使用
    }
}
```

7. 箭头函数

箭头函数中的this是当前箭头函数之外最近的作用域的this

  • 几乎所有的匿名函数都可用箭头函数简化
  • 箭头函数是大多匿名函数的简写
// 关于箭头函数和普通函数的this区别
var lilei={
    name:"Li Lei",
    friends:["涛涛","楠楠","东东"],
    intr:function(){
        this.friends.forEach(function(元素值n){
            console.log(`${this.name}认识${元素值n}`)
        })
    }
}
lilei.intr();   // 输出结果: undefined认识涛涛   undefined认识楠楠   undefined认识东东
// 解析:intr的方法中的this指向调用该方法的对象lilei
// 所以this.friends得到了lilei.friends
// 当this.friends循环遍历时,forEach中接收的回调函数没有人调用它,所以它里面的this指向window,访问this.name时就是undefined了。
    
// 把forEach中接收的回调函数改成箭头函数:
lilei.intr = function(){
    this.friends.forEach((元素值n)=>{
        console.log(`${this.name}认识${元素值n}`)
    })
}
lilei.intr();   // 输出:Li Lei认识涛涛   Li Lei认识楠楠   Li Lei认识东东
// 改成箭头函数后,箭头函数的this是指向它自己外面最近的作用域的this
// 也就是和intr这个函数作用域的this指向相同,即指向lilei这个对象
// 此时的this.name就取到了lilei.name。

【注】如果上面案例中,intr方法的普通函数改成箭头函数的话,此时this.friends为undefined了,因为箭头函数指向intr外的作用域,即lilei对象外的作用域,也就是指向window了。

结论

①:在使用this时,如果希望函数内外的this保持一致,就可以使用箭头函数;

②:当不希望函数内外的this指向一样的时候,就不能用箭头函数。

【注】箭头函数只是改变了自身的this指向,不影响自身的局部变量作用域。箭头函数内部定义的变量仍是局部变量,只能在箭头函数内使用,在箭头函数外部无法访问该变量。

箭头函数的底层原理和bind的效果一样

8. 改变this的方法

  • call:①使用call会立即调用函数;②函数中this指向call的第一个参数;③call接收两个以上实参,可以将第二个及以后的参数传给函数

  • apply:①使用apply会立即调用函数;②函数中this指向apply的第一个参数;③apply接收两个实参,第二个参数是个数组,apply将第二个参数的数组按顺序拆散成多个实参传给函数。

    function fun(params1, params2) {
        console.log(this.name)
        console.log(params1, params2)
       }
    var lilei = {name: 'LiLei'}
    var hanmei = {name: 'HanMei'}
    fun.call(lilei, 'lilei~', '20');    // LiLei lilei~ 20
    fun.apply(hanmei, ['hanmei~', '18']);   // HanMei hanmei~ 18
    
  • bind:①创建一个跟原函数一样的新函数,但不执行;②永久的替换新函数中的this指向;③bind可以接收其他实参做永久替换部分形参变量为固定的实参值

    function fun(...arg) {
        console.log(this.name)
        console.log(...arg)
    }
    // bind返回的新函数可以多次调用
    var zhangsan = {name: 'ZhangSan'}
    var zsfun = fun.bind(zhangsan)
    zsfun(1, 2, 3); // 输出结果:ZhangSan 1 2 3
    zsfun('zs');    // 输出结果:ZhangSan zs
    // bind绑定永久参数
    var zsfun2 = fun.bind(zhangsan, 100, 200)
    zsfun2(1, 2, 3);  // 输出结果:ZhangSan 100 200 1 2 3
    zsfun2('zs');   //输出结果:ZhangSan 100 200 zs
    

image-20220210162536789.png

【注】

  1. 被bind()永久绑定的this,即便用call,也无法修改this的指向了,即多次bind绑定也只有第一次的生效

  2. new操作的绑定操作优先度要高于bind,也会高于apply和call

总结:this指向

  1. 在全局作用域中,this指向window
  2. 在class中,this指向新创建的类实例
  3. 在函数中的this:

image-20220210164209652.png