Skip to content

箭头函数与普通函数的区别

Posted on:August 21, 2021
  1. 箭头函数没有 prototype,所以箭头函数本身没有 this

    this存在的其中一个目的是可以改变函数的上下文,改变了上下文就改变了函数的原型prototype,那箭头函数没有this也就没有prototype
    ```js
      // 箭头函数
      let a = () => {};
      console.log(a.prototype); // undefined
    
      // 普通函数
      function a() {};
      console.log(a.prototype); // {constructor:f}
    
    ```

  2. 箭头函数不会创建自己的 this

    箭头函数没有自己的 this,箭头函数的 this 指向在定义的时候继承自外层第一个普通函数的 this。

    var id = "Global";
    
    function fun1() {
      // setTimeout中使用普通函数
      setTimeout(function () {
        console.log(this.id);
      }, 2000);
    }
    
    function fun2() {
      // setTimeout中使用箭头函数
      setTimeout(() => {
        console.log(this.id);
      }, 2000);
    }
    
    fun1.call({ id: "Obj" }); // 'Global'
    
    fun2.call({ id: "Obj" }); // 'Obj'

    函数 fun1 中的 setTimeout 中使用普通函数,2 秒后函数执行时,这时函数其实是在全局作用域执行的,所以 this 指向 Window 对象,this.id 就指向全局变量 id,所以输出’Global’。 但是函数 fun2 中的 setTimeout 中使用的是箭头函数,这个箭头函数的 this 在定义时就确定了,它继承了它外层 fun2 的执行环境中的 this,而 fun2 调用时 this 被 call 方法改变到了对象{id: ‘Obj’}中,所以输出’Obj’。

    var id = "GLOBAL";
    var obj = {
      id: "OBJ",
      a: function () {
        console.log(this.id);
      },
      b: () => {
        console.log(this.id);
      },
    };
    
    obj.a(); // 'OBJ'
    obj.b(); // 'GLOBAL'

    对象 obj 的方法 a 使用普通函数定义的,普通函数作为对象的方法调用时,this 指向它所属的对象。 所以,this.id 就是 obj.id,所以输出’OBJ’。 但是方法 b 是使用箭头函数定义的,箭头函数中的 this 实际是继承的它定义时所处的全局执行环境中的 this,所以指向 Window 对象,所以输出’GLOBAL’。(这里要注意,定义对象的大括号{}是无法形成一个单独的执行环境的,它依旧是处于全局执行环境中!!)


  1. call | apply | bind 无法改变箭头函数中 this 的指向

    call | apply | bind 方法可以用来动态修改函数执行时 this 的指向,但由于箭头函数的 this 定义时就已经确定且永远不会改变。所以使用这些方法永远也改变不了箭头函数 this 的指向。

    var id = "Global";
    // 箭头函数定义在全局作用域
    let fun1 = () => {
      console.log(this.id);
    };
    
    fun1(); // 'Global'
    // this的指向不会改变,永远指向Window对象
    fun1.call({ id: "Obj" }); // 'Global'
    fun1.apply({ id: "Obj" }); // 'Global'
    fun1.bind({ id: "Obj" })(); // 'Global'

  1. 箭头函数不能作为构造函数使用

    我们先了解一下构造函数的new都做了些什么?简单来说,分为四步:
    
    - JS内部首先会先生成一个对象;
    - 再把函数中的this指向该对象;
    - 然后执行构造函数中的语句;
    - 最终返回该对象实例。
    
    <br>
    
    但是!!因为箭头函数没有自己的this,它的this其实是继承了外层执行环境中的this,且this指向永远不会随在哪里调用、被谁调用而改变,所以箭头函数不能作为构造函数使用,或者说构造函数不能定义成箭头函数,否则用new调用时会报错!
    ```js
    let Fun = (name, age) => {
        this.name = name;
        this.age = age;
    };
    
    // 报错
    let p = new Fun('cao', 24);
    
    ```

  2. 箭头函数没有自己的 arguments

    箭头函数没有自己的 arguments 对象。在箭头函数中访问 arguments 实际上获得的是外层局部(函数)执行环境中的值。

    // 例子一
    let fun = val => {
      console.log(val); // 111
      // 下面一行会报错
      // Uncaught ReferenceError: arguments is not defined
      // 因为外层全局环境没有arguments对象
      console.log(arguments);
    };
    fun(111);
    
    // 例子二
    function outer(val1, val2) {
      let argOut = arguments;
      console.log(argOut); // ①
      let fun = () => {
        let argIn = arguments;
        console.log(argIn); // ②
        console.log(argOut === argIn); // ③
      };
      fun();
    }
    outer(111, 222);

    普通函数 outer 内部的箭头函数 fun 中的 arguments 对象,其实是沿作用域链向上访问的外层 outer 函数的 arguments 对象。 可以在箭头函数中使用 rest 参数代替 arguments 对象,来访问箭头函数的参数列表!!


  1. 箭头函数不能用作 Generator 函数,不能使用 yeild 关键字