关于 this 的指向问题

144 阅读2分钟

1.关于 this 指向的几种情况

  • 以函数形式调用时, this 永远都是 window
  • 以方法的形式调用时,this 是调用方法的对象
  • 以构造函数的的形式调用时,this 是新创建的那个对象
  • 定时器和计时器的 this 默认指向 window
  • 箭头函数的 this 看外层是否有函数:如果有,外层函数的 this 就是内部箭头函数的this,如果没有,就是 window
  • 严格模式下(设置了'use strict'),this为undefined
  • 特殊情况:通常意义上 this 指向最后调用它的对象,这里需要注意的一点是,如果返回值是一个对象,那么 this 指向的就是那个返回值的对象,如果返回值不是一个对象,那么 this 还是指向函数的实例
 <script>
        function fn() {
            console.log(this, '1')//window
        }
        fn()//调用才会打印

        let obj = {
            name: '前端小白兔',
            age: 18,
            eat: function () {
                console.log(this, '2')//Object
                setTimeout(function () {
                    console.log(this, '3')//window
                }),
                setTimeout(()=>{
                    console.log(this,'4')//Object
                })
            },

        }
        obj.eat()//调用才会打印

        function Person(name, age) {
            this.name = name,
            this.age = age,
            this.sayHi = function () {
                    console.log(this, '5')//new Person
                    return `我是${this.name},今年${age}岁!`
                }
        }
        let p = new Person('Lucy', 18)
        p.sayHi()//调用才会打印


        setTimeout(function () {
            console.log(this, '6')//window
        }, 1000)

        setInterval(function () {
            console.log(this, '7')//window
        }, 5000)

        function getSum() {
            'use strict'
            console.log(this, '8')//undefined
        }
        getSum()//调用才会打印
 </script>

image.png

2.修改 this 指向的方式

使用函数上下文调用模式 : 修改this指向

  • 函数名.call(修改后的this,实参1,实参2......),适用于少量形参
  • 函数名.apply(修改后的this,数组/伪数组),适用于多个形参
  • 函数名.bind(修改后的this,实参1,实参2......),适用于不需要立即执行的函数(定时器函数,事件处理函数),得到一个修改this之后的新函数
<script>
        //◆函数名.call(修改后的this,实参1,实参2......)
        function fn1(a, b) {
            console.log(this, '1')
            return a + b
        }

        fn1.call({ name: '张三' }, 20, 80)

        //◆函数名.apply(修改后的this,数组/伪数组)
        function fn2(a, b, c) {
            console.log(this, '2')

        }
        fn2.apply({ name: '李四' }, [20, 80, 90])
        
       //◆函数名.bind(修改后的this,实参1,实参2......)
        function fn(a, b) {
            console.log(this, '3')
            return a * b
        }
        let newFn = fn.bind([50, 100], 50, 100)
        console.log(newFn(70,80),'6')//5000


        // 具名函数
       function test() {
            console.log(this, '4')
        }
        setTimeout(test.bind({ name: '前端小白兔' }), 2000)

        // 匿名函数
        setTimeout(function () {
            console.log(this, '5')
        }.bind({ name: '斩妖除魔' }), 2000)
        
    </script>

image.png

小细节:如果调用bind传递了参数,则参数也会绑定,之后调用的时候无法传参; 如果bind绑定的时候不传参数,则不绑定参数,后面就可以传其他的参数

3.函数上下文三种调用方式的区别

  1. 传参方式不同:call 用于单个传参,apply 用于多个传参
  2. 执行机制不同:call 和 apply 会立即执行,bind 不会立即执行

4.函数上下文调用模式中:this 指向只能是引用类型

如果你传的不是引用类型,编译器会自动帮你转成对应的引用类型

<script>
        function fn() {
            console.log(this)
        }
        fn.call(1)//内置对象Number
        fn.call('你好呀上帝')//内置对象String
        fn.call(Symbol('A'))//内置对象Symbol
        fn.call(undefined)//window
        fn.call(null)//window
        fn.call()//window
 </script>

如果 this 修改为 undefined 或 null ,此时 this 修改无效的,还是之前的this

image.png