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

105 阅读2分钟

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

不同点

  • 写法
    • 箭头函数使用箭头定义
    • 普通函数没有使用箭头定义
  • 匿名函数
    • 箭头函数都是匿名函数
    • 普通函数可以是匿名函数,也可以是具名函数
  • this指向
    • 普通函数中
      • 在普通函数中,this 的指向(执行上下文)是动态的,其值取决于函数是如何被调用的:
        1. 直接调用时,其指向为全局对象(严格模式下为 undefined)
        2. 方法调用时,其指向为调用该方法的对象
        3. new 调用时,其指向为新创建的实例对象
        4. call、apply、bind 调用时,其指向为三种方法的第一个参数
    • 无论如何执行或在何处执行,箭头函数内部的 this 值始终等于外部函数的值,即箭头函数不会改变 this 的指向,
      • 注意:由于箭头函数没有自己的 this 指针,通过 call() 、 apply() 和 bind() 方法调用时,只能传递参数,而不能绑定 this,他们的第一个参数会被忽略。
  • 构造函数
    • 在 JavaScript 中,函数和类的继承是通过 prototype 属性实现的,且 prototype 拥有属性 constructor 指向构造函数
    • 而采用箭头函数定义函数时,其是没有 prototype 属性的,也就无法指向构造函数。
      • 没有自己的 this,也就意味着无法调用 apply、call 等
      • 没有 prototype 属性,而 new 命令在执行时需要将构造函数的 prototype 赋值给新的对象的 proto
          function newOperator(Con, ...args) {
              let obj = {};
              Object.setPrototypeOf(obj, Con.prototype); // 相当于 obj.__proto__ = Con.prototype
              let result = Con.apply(obj, args);
              return result instanceof Object ? result : obj;
          }
      

      更具体的原因是,JavaScript函数两个内部方法: [[Call]] 和 [[Construct]],当函数被直接调用时执行的是 [[Call]] 方法,即直接执行函数体,而 new 调用时是执行的 [[Construct]]方法。箭头函数没有 [[Construct]]方法,因此不能被用作构造函数进行实例化。

为什么箭头函数不能构造实例对象

function newFunc(father, ...rest) {
  var result = {}; // 1. 创建空对象result
  result.__proto__ = father.prototype; // 2. 将空对象result的原型链指向构造器father的原型
  var result2 = father.apply(result, rest); // 3. 将fathe函数中的this指向result【若此处father为箭头函数而没有自己的this,call()函数无法改变箭头函数的指向,也就无法指向result。】
  if (
    (typeof result2 === 'object' || typeof result2 === 'function') &&
    result2 !== null
  ) {
    return result2;
  }
  return result;
}

普通函数

this的优先级如下

  1. new
  2. call bind apply 等硬绑定
  3. 上下文对象中调用(隐式绑定)
  4. 默认绑定,即指枪全局对象

参考资料

普通函数与箭头函数的区别是什么?