• Home
  • Explore
  • Detail

箭头函数的意义和函数的二义性

22 views

前言 谈起箭头函数,可能很多人都非常熟悉,在日常开发中可以说跟喝水一样重要。谈起与普通函数的区别,更是信手拈来: - 箭头函数没有独立的 this、arguments 和 super 绑定,并且不可被用作方法。 - 箭头函数不能用作构造函数。使用new调用它们会引发TypeError 。它们也无法访问new.target关键字。 - 箭头函数不能在其主体中使用yield,也不能作为生成器函数创建。 虽然区别上多少都能罗列一些,但是为什么JS已经有了普通函数了,为什么仍然要有箭头函数?难道只是为了一个语法简单? > 答案是:为了消除函数的二义性。 ## 什么是函数的二义性 我们知道,在JS中,调用一个函数可以有以下两种方式: js function f() {} // 构造函数调用 let a = new F(); // f{} // 普通函数调用 let b = f(); // undefined 不同的调用方式体现出对函数f的不同理解,并且有着不同的调用结果,这就是函数的二义性。 因为二义性的存在,导致JS函数的复杂度直线上升,因为在函数创建的时候,创建者无法预知其未来如何被调用,导致存在很大的安全隐患。 > 虽然多数情况下这种歧义可以被避免,例如JS命名规范中建议使用大写字母开头的函数名来表示构造函数,小写字母开头的函数名表示普通函数,使代码更易于理解和维护。但因为这并非强制要求,所以歧义仍然存在。 > > 如果你不想函数被通过new来调用,可以这样: > js > function f() { > if (new.target) { > throw('Uncaught TypeError: f is not a constructor') > } > } > 这个二义性给开发者造成严重的心智负担,官方一直知道这个问题,只是一直没有解决,后来在ES6中引入了两个概念: - 箭头函数 - class 它们的作用都是为了消除函数的二义性。 箭头函数只能这样使用: js const f = () => {}; // 报错 Uncaught TypeError: f is not a constructor const a = new f(); // 正确 f(); class只能这样使用: js class F{}; // 报错 Uncaught TypeError: Class constructor F cannot be invoked without 'new' const f = F(); // 正确 const f = new F(); 为什么箭头函数里没有this和原型? js const f = () => {}; console.log(f.prototype); // undefined 因为箭头函数跟实例无关,跟面向对象没关系,它已经脱离了面向对象的范畴,而this哪来的?this来自于面向对象里面的概念,箭头函数里面没有原型的概念是一样的。