跳到主要内容

箭头函数

this 绑定原则

箭头函数中,this与封闭词法环境的this保持一致。

  • 箭头函数this指向创建该函数时所在的上层作用域
  • 箭头函数this的绑定与**定义的位置(编写的位置)**有关系
  • 箭头函数的 this调用的位置没关系
  • 箭头函数this在函数创建时绑定。

内置函数中的 this 绑定


DOM 事件中的 this 绑定

  • 通过onclick绑定事件: 箭头函数与调用环境无关,this指向在创建时已经绑定。

    <div class="box">点击事件</div>
    <script>
    const box = document.querySelector(".box");
    box.onclick = (e) => {
    console.log(e);
    console.log(this); // 指向 Window {window: Window, self: Window, document: document, name: '', location: Location, …}
    };
    </script>
  • 通过addEventListener绑定事件: 箭头函数与调用环境无关,this指向在创建时已经绑定

    <div class="box">点击事件</div>
    <script>
    const box = document.querySelector(".box");
    box.addEventListener("click", (e) => {
    console.log(e);
    console.log(this); // 指向 Window {window: Window, self: Window, document: document, name: '', location: Location, …}
    });
    box.addEventListener("click", (e) => {
    console.log(e);
    console.log(this); // 指向 Window {window: Window, self: Window, document: document, name: '', location: Location, …}
    });
    box.addEventListener("click", (e) => {
    console.log(e);
    console.log(this); // 指向 Window {window: Window, self: Window, document: document, name: '', location: Location, …}
    });
    </script>

setTimeout 中的 this 绑定

  • 普通函数: 该函数独立调用,this 绑定到了全局执行上下文 window

    setTimeout(function(){
    console.log(this); // 该函数独立调用,this 绑定到了全局执行上下文 window
    },200);
  • 箭头函数: 该函数创建环境所在的上层作用域为全局,所以 this 指向为 window

    setTimeout(() => {
    console.log(this); // Window {window: Window, self: Window, document: document, name: '', location: Location, …}
    }, 200);

JS 数组方法中的 this 绑定

  • 普通函数: 箭头函数创建时的上层作用域为全局,所以 this 指向 window

    const array = ["a", "b", "c"];
    array.forEach((value, index, arr) => {
    console.log(value, index, arr); // a 0 (3) ['a', 'b', 'c'] 循环遍历 arr 指向数组
    console.log(this); // this 指向 window
    });
  • 构造函数: 虽然 forEach 内部有对回调函数修改 this 指向,但是箭头函数的 this 只与创建该函数时的上层作用域有关,上层作用域为全局,this 指向 window

    const array = ["a", "b", "c"];
    array.forEach((value, index, arr) => {
    console.log(value, index, arr); // a 0 (3) ['a', 'b', 'c'] 循环遍历 arr 指向数组
    console.log(this); // this 指向 window
    },array);

this 面试常考问题


  • 根据问题,输出结果--forEach 改变 this 指向

    function foo (value){
    console.log(value,this.name);
    }
    const obj = {
    name:'柏拉文'
    };
    [1,2,3].forEach(foo,obj);
    // 结果为:
    // 1 '柏拉文'
    // 2 '柏拉文'
    // 3 '柏拉文'
  • 根据问题,输出结果,并改正--对象属性为函数,且函数里面嵌套函数

    • this 指向 window

      const obj = {
      data:[],
      getData:function(){
      setTimeout(function(){
      this.data = [1,2,3]; // setTimeout 中的 callback 回调函数是 window 调用的,所以回调函数中的 this 指向 window , this.data === window.data
      console.log(this,this.data); // window window.data = [1,2,3]
      },100);
      }
      }

      obj.getData();
    • 更改 this 指向方案一: 将 this 赋值给另一个变量保存指向

      const obj = {
      data:[],
      getData:function(){ // getData 函数被 obj 对象调用,所以 getData 函数中的 this 指向 obj
      const that = this; // 将 this 赋值给 that , that 指向 obj
      setTimeout(function(){
      that.data = [1,2,3];
      console.log(that,that.data);
      },100);
      }
      }

      obj.getData();
    • 更改 this 指向方案二 将自身调用的函数通过 bind 绑定指向

      const obj = {
      data:[],
      getData:function(){
      setTimeout(function(){
      this.data = [1,2,3];
      console.log(this,this.data);
      }.bind(this),100);
      }
      }

      obj.getData();
    • 更改 this 指向方案三 将自身调用的函数使用箭头函数

      const obj = {
      data:[],
      getData:function(){
      setTimeout(()=>{
      this.data = [1,2,3];
      console.log(this,this.data);
      },100);
      }
      }

      obj.getData();
  • 根据问题,说出输出结果--对象函数相互嵌套之对象属性

    var name = "windowName";
    var person = {
    name: "person",
    sayName: function () {
    console.log(this.name);
    },
    };
    function sayName() {
    var sss = person.sayName;
    sss(); // 自身独立函数调用,this 指向为 window ====> 结果为 windowName
    person.sayName(); // person 隐式调用, this 指向为 person ====> 结果为 person
    (person.sayName)(); // person 隐式调用, this 指向为 person ====> 结果为 person
    (b = person.sayName)(); // 自身独立函数调用, this 指向为 window ====> 结果为 windowName
    }
    sayName();
  • 根据问题,说出输出结果--对象函数相互嵌套之 call 与 this

    var name = "windowName";
    var person1 = {
    name:'person1Name',
    foo1:function(){
    console.log(this.name);
    },
    foo2:()=>{
    console.log(this.name);
    },
    foo3:function(){
    return function(){
    console.log(this.name);
    }
    },
    foo4:function(){
    return ()=>{
    console.log(this.name);
    }
    }
    }
    var person2 = {name:"person2Name"};
    person1.foo1(); // person1 隐式绑定,this 指向为 person1 ====> 结果为 person1Name
    person1.foo1.call(person2); // person1 隐式绑定 、 person2 显示绑定 ,且显示绑定优先级高于隐式绑定,this 指向为 person2 ====> 结果为 person2Name
    person1.foo2(); // person1 调用 foo2 ,但是 foo2 为箭头函数,不绑定 this ,所以 foo2 中的 this 指向根据外层作用域决定, foo2 的上层作用域为 window (注意对象不是作用域,作用域只包括全局、函数、块级),所以 this 指向为 window ====> 结果为 windowName
    person1.foo2.call(person2); // person1 调用 foo2 ,且 通过 call 指向了 person 2 。但是 foo2 为箭头函数,不绑定 this ,所以 foo2 中的 this 指向根据上层作用域决定, foo2 的上层作用域为 window (注意对象不是作用域,作用域只包括全局、函数、块级),所以 this 指向为 window ====> 结果为 windowName
    person1.foo3()(); // person1.foo3() 返回一个函数,并且自身独立调用 ===> 结果为 windowName
    person1.foo3.call(person2)(); // person1.foo3.call(person2) 相当于 person1.foo3() 且里面的 this 指向为 person2 ,但是 person1.foo3()() 还是自身独立调用 ===> 结果为 windowName
    person1.foo3().call(person2); // person1.foo3() 返回一个函数,这个返回的函数通过 call 将自身的 this 指向了 person2 ===> 结果为 person2Name
    person1.foo4()(); // person1.foo4() 返回一个箭头函数,并且自身独立调用但是这个箭头函数的上层作用域为 person.foo4() ,所以该箭头函数调用时,this 指向的是上层作用域 person.foo4() 里面的 this,而 person.foo4() 里面的 this 指向 person1 ===> 结果为 person1Name
    person1.foo4.call(person2)(); // person1.foo4.call(person2) 相当于 person1.foo4() 且里面的 this 指向为 person2, person1.foo4.call(person2) 返回一个箭头函数,箭头函数独立调用,但是箭头函数不绑定 this,由上层作用域决定,箭头函数的上层作用域为 person1.foo4(),此时 person1.foo4() 中的 this 通过 call 指向了 person2 ===> 结果为 person2Name
    person1.foo4().call(person2); // person1.foo4() 返回了一个箭头函数,并且通过 call 改变this但是箭头函数不绑定 this ,所以该箭头函数调用时,this 指向的是上层作用域 person.foo4() 里面的 this,而 person.foo4() 里面的 this 指向 person1 ===> 结果为 person1Name
  • 根据问题,说出输出结果--对象函数相互嵌套之 new、call 与 this

    var name = 'windowName';
    function Person(name){
    this.name = name;
    this.foo1 = function(){
    console.log(this.name);
    }
    this.foo2 = ()=> console.log(this.name);
    this.foo3 = function(){
    return function(){
    console.log(this.name);
    }
    }
    this.foo4 = function(){
    return ()=>{
    console.log(this.name);
    }
    }
    }

    var person1 = new Person('person1Name');
    var person2 = new Person('person2Name');

    person1.foo1();// person1 调用 foo1() ,隐式绑定 this,this 指向 person1 ===> 结果为 person1Name
    person1.foo1.call(person2);//person1 调用 foo1(), 通过 call 显示绑定 this 到 person2 ,this 指向 person2 ===> 结果为 person2Name
    person1.foo2();//person1 调用 foo2() , 隐式绑定 this 。但是 foo2 为箭头函数,箭头函数不绑定 this ,里面的 this 由上层作用域决定,foo2 箭头函数的上层作用域为 Person ,而 foo2 是通过 person1 调用的,所以 此时 Person 的 this 指向 person1 ==> 结果为 person1Name
    person1.foo2.call(person2);//person1 调用 foo2(), 通过 call 显示绑定 this。但是 foo2 为箭头函数,箭头函数不绑定 this ,里面的 this 由上层作用域决定,foo2 箭头函数的上层作用域为 Person, 而 foo2 是通过 person1 调用的,所以此时 Person 的 this 指向person1 ==> 结果为 person1Name
    person1.foo3()();// person1.foo3() 返回一个普通函数,普通函数自身独立调用 , this 指向 window ===> 结果为 windowName
    person1.foo3.call(person2)();// person1.foo3 函数通过 call 改变了 person1.foo3 中的 this 指向,返回了一个普通函数,普通函数自身独立调用 , this 指向 window ===> 结果为 windowName
    person1.foo3().call(person2);// perso1.foo3 函数返回了一个普通函数,这个普通函数通过 call 显示绑定自身 this 指向为 person2 ===> 结果为 person2Name
    person1.foo4()();// person1.foo4() 函数返回了一个箭头函数,箭头函数自身独立调用。但是箭头函数自身不绑定 this, 箭头函数的 this 要看上层作用域,该箭头函数的上层作用域为 person1.foo4() ,person1.foo4() 中的 this 指向 person1,所以该箭头函数 this 也指向 person1 ===> 结果为 person1Name
    person1.foo4.call(person2)();// person1.foo4 函数通过 call 显示绑定自身 this 指向为 person2,并且返回一个箭头函数,箭头函数自身独立调用。但是箭头函数自身不绑定 this, 箭头函数的 this 要看上层作用域,该箭头函数的上层作用域为 person1.foo4() ,person1.foo4() 中的 this 通过 call 显示绑定了 person2,所以该箭头函数 this 也指向 person2 ===> 结果为 person2Name
    person1.foo4().call(person2);// person。foo4 函数返回一个箭头函数,箭头函数通过 call 显示绑定 this 指向为 person2。但是箭头函数自身不绑定 this, 箭头函数的 this 要看上层作用域,该箭头函数的上层作用域为 person1.foo4() ,person1.foo4() 中的 this 指向为 person1,所以该箭头函数 this 也指向 person1 ===> 结果为 person1Name
  • 根据问题,说出输出结果--对象函数相互嵌套之 new、call 与 this 加强版

    var name = "window";
    function Person(name){
    this.name = name;
    this.obj = {
    name:'obj',
    foo1:function(){
    return function (){
    console.log(this.name);
    }
    },
    foo2:function(){
    return ()=>{
    console.log(this.name);
    }
    }
    }
    }

    var person1 = new Person('person1');
    var person2 = new Person('person2');

    person1.obj.foo1()();// person1.obj 调用 foo1 函数,返回一个普通函数。普通函数自身独立调用,this 指向 window ===> 结果为 window
    person1.obj.foo1.call(person2)();// person1.obj 通过 call 显示绑定 foo1 函数中的 this 指向为 person2,返回一个普通函数。普通函数自身独立调用,this 指向 window ===> 结果为 window
    person1.obj.foo1().call(person2);// person1.obj 调用 foo1 函数,返回一个普通函数。普通函数通过 call 显示绑定 自身this 指向为 person2 ===> 结果为 person2
    person1.obj.foo2()();// person1.obj 调用 foo2,返回一个箭头函数。箭头函数自身独立调用,但是箭头函数不绑定 this ,自身this 跟随上层作用域。该箭头函数的上层作用域为 obj.foo2(),obj.foo2() 的 this 指向为 obj,所以该箭头函数的 this 指向为 obj ==> 结果为 obj
    person1.obj.foo2.call(person2)();// person.obj 通过 call 显示绑定 foo2 函数中 this 指向为 person2,返回一个箭头函数。箭头函数自身独立调用,但是箭头函数不绑定 this ,自身this 跟随上层作用域。该箭头函数的上层作用域为 obj.foo2(),obj.foo2() 的 this 通过 call 显示绑定为 person2,所以该箭头函数的 this 指向为 person2 ==> 结果为 person2
    person1.obj.foo2().call(person2);// person.obj 调用 foo2 函数,返回一个箭头函数。箭头函数通过 call 显示绑定 this 为 person2,但是箭头函数不绑定 this ,自身this 跟随上层作用域。该箭头函数的上层作用域为 obj.foo2(),obj.foo2() 的 this 指向为 obj,所以该箭头函数的 this 指向为 obj ==> 结果为 obj