函数this的指向

84 阅读1分钟

环境对象

环境对象this: 谁调用我我就是谁

this指向取决于函数的调用:

  • 普通函数 : 函数名() this->window
  • 构造函数 : new 函数名() this->new创建的实例对象
  • 对象方法: 对象名.方法() this->对象
<script>
        function fun(params) {
           console.log(this);
       }
       // 1.普通函数
       fun() //window
       // 2.构造函数
       new fun() //new创建的对象
       let obj = {
           name: '万叶',
           age: 18,
           eat: fun
       }
       // 3.对象方法
       obj.eat() //obj
   </script>

总结: this指向三选一,先找new,后找点

修改this的指向的三种方法

默认情况下,函数内的this是固定的,无法被修改

如果想要修改函数内部this的指向,则需要使用上下文调用方法

上下文: 函数作用域 上下文只想:修改函数作用域内部this指向

1.call方法调用,同时指定被调用函数中this的值

<script>
    // call方法调用,同时指定被调用函数中this的值
    // 语法:
    // fun.call(thisArg,arg1,arg2...)
    // thisArg:在tun函数运行时指定的this值
    // arg1,arg2:传递其他的参数
    // 返回值就是函数的返回值,因为他就是调用函数
    const obj = {
      name: '万叶'
    }

    function fun(x, y) {
      console.log(this); //window
      console.log(x + y); //3
    }
    // 1.调用函数
    // 2.改变this指向
    fun.call(obj, 1, 2)
  </script>

2.指向apply方法调用函数,同时指定被调用函数中this的值

  <script>
    // 语法:
    // fun.apply(thisArg,[argsArray])
    // thisArg:在fun函数运行时指定的this值
    // argsArray:传递的值,必须包含在数组里面
    // 返回值就是函数的返回值,因为就是在调用函数
    // 因此apply主要跟数组有关系,比如使用Math.max()求数组的最大值
      function fun(x, y) {
      return x + y
    }
    // 调用函数,并传入参数
    let fu = fun.apply(null, [1, 2])
    console.log(fu); //3
  </script>

apply的运用场景: 伪数组转真数组

<script>
        // apply()使用场景:伪数组转真数组
        // 1. 伪数组: 有数组三要素(下标,元素,长度),不能使用数组的方法
        //伪书组本质是对象
        let obj = {
            0: 1,
            1: 2,
            2: 3,
            length: 3
        }
        console.log(obj);
        // 需求:有时候伪书组想要使用真数组的办法,就需要把为数组转换为真数组
        // 1.把为数组元素取出来,push到真数组里面
        let arr = []
        arr.push(obj[0], obj[1], obj[2])
        console.log(arr);
        // 2.手动遍历循环添加
        let arr = []
        for (let i = 0; i < obj.length; i++) {
            arr.push(obj[i])
        }
        console.log(arr);
        //3.arr.push.apply(arr.为数组)
        // 这里使用apply不是为了修改this,而是借助传参特点,自动遍历为数组/数组传参,多余第一个参数应该写arr(保持this不变)
        let arr = []
        arr.push.apply(arr, obj)
        console.log(arr);
        // ES6:为数组换真数组,固定静态方法Array.from(伪数组)
        let newArr = Array.from(obj)
        console.log(obj);
    </script>

apply的运用场景: 求最大值

    <script>
        // apply(场景;求数组最大值)
        let arr = [100, 200, 300, 400]
        // 1.js基础:擂台思想
        let max = arr[0]
        for (let i = 0; i < arr.length; i++) {
            max = max > arr[i] ? max : arr[i]
        }
        console.log(max);
        // 2.js高级Math.amx()
        let max1 = Math.max.apply(Math, arr)
        console.log(max1);
        //ES6: Math.max(...arr)
        let max2 = Math.max(...arr)
        console.log(max2);
    </script>

3.bind()方法不会调用函数,但是能改变函数内部的this指向

<script>
     // 语法:
    // fun.bind(thisArg, arg1, arg2, ...)
    // thisArg:在fun函数运行时指定的this值
    // arg1, arg2:传递的其他参数
    // 返回由指定this值和初始化参数改造的原函数拷贝(新函数)
    // 因此当我们只想改变this指向,并且不想调用这个函数的时候,可以使用bind,比如改变定时器内部this指向
    const obj = {
      age: 18
    }

    function fun() {
      console.log(this);
    }
    // 1.bind不会调用函数
    // 2.改变this指向
    // 3.返回值是个函数,但是这个函数里面的this时更改过的
    const fu = fun.bind(obj)
    fun() //window
    //改变this指向的函数
    fu() //obj
  </script>

总结:

  • 相同点:
    • 都可以改变函数内部的this指向
  • 区别点:
    • call和apply会调用函数,并且改变函数内部this指向
    • call和apply传递的参数不一样, call传递参数aru1, aru2...形式apply必须数组形式[arg]
    • bind不会调用函数,可以改变函数内部this指向
  • 主要应用场景:
    • call调用函数并且可以传递参数
    • apply经常跟数组有关系,比如借助于数学对象实现数组最大值最小值
    • bind不调用函数,但是改变this指向比如改变定时器内部this的指向