箭头函数是不可追踪的吗?
不,如果您指的是能够调试它们、堆栈跟踪等,它们与任何其他函数一样可追溯。
我刚刚了解到,写这个...比这个更糟糕...
不,不是。这不一样。这在客观上并不不好。¹
原因是第一种方法很难调试与该函数相关的问题,因为它不会出现在堆栈跟踪中。
是的,它会的。如果有人告诉你它不会,那他们就错了?——这是可以理解的,因为箭头函数没有声明语法,而且它们的表达式语法没有任何地方可以放置名称;所以假设他们没有名字似乎是合理的。虽然有些人不这样做,但很多人这样做(有关方式和时间的详细信息,请参阅my answer here),包括您的。让我们在堆栈跟踪中查看名称:
const setName = name => {
throw new Error("Ack!");
};
const wrapper = name => setName(name);
wrapper("foo");
Look in the real console.
如果你运行它,你会在控制台中看到这个:
注意setName 和wrapper 是如何列出的。
因此,即使是使用匿名语法创建的函数也可以(有点自相矛盾地)获得名称,而且经常这样做。这不仅仅是特定的 JavaScript 引擎提供的帮助(尽管它曾经是),它是由 JavaScript 规范规定的。
那么什么是匿名函数语法与命名函数语法?让我们快速回顾一下创建函数的五种常用方法(这不是完整的列表——I provide one here——只有五种常用方法):
-
函数声明(^ 标记表示声明本身,− 标记表示函数的内容):
function example1() { return 42; }
// ^^^^^^^^^^^^^^^^^^^^^−−−−−−−−−−−−^
-
命名函数表达式(相对很少见):
const example = function example2() { return 42; };
// ^^^^^^^^^^^^^^^^^^^^^−−−−−−−−−−−−^
-
匿名function 表达式:
const example3 = function() { return 42; };
// ^^^^^^^^^^^^−−−−−−−−−−−−^
-
一个“详细”的箭头函数表达式(有一个函数体块,没有隐含的return):
const example4 = () => { return 42; };
// ^^^^^^^−−−−−−−−−−−−^
-
一个“简洁”的箭头函数表达式(没有函数体块,隐含return):
const example5 = () => 42;
// ^^^^^−−−
function 声明总是包含一个名称(有一个模糊的例外²)。 function 表达式可以命名或匿名。所有箭头函数表达式都是匿名的。但是这些示例中的所有函数都有名称(example1、example2、example3、example4 和 example5)。他们的名字是根据他们所属的表达式分配的。 (详情请参阅the answer linked earlier。)
明确一点:一些箭头函数没有名称,就像一些传统函数没有名称一样。例如,这些函数都没有名称:
result = theArray.map(s => s.toUpperCase());
result = theArray.map(function(s) { return s.toUpperCase(); });
传统函数相对于箭头函数的名称的唯一优势在于,它们的表达式语法允许您显式指定名称而不是依赖于上下文,如下所示:
result = theArray.map(function upperCaseCallback(s) { return s.toUpperCase(); });
没有办法在带有箭头函数的单个表达式中做到这一点,你需要这样的东西:
const upperCaseCallback = s => s.toUpperCase();
result = theArray.map(upperCaseCallback);
但即使某些箭头函数是匿名的,您的示例却不是。
¹ 事实上,有一些相反的说法:箭头函数没有prototype 属性和与之关联的对象,调用它不需要设置新的this 绑定或arguments 伪对象和绑定(因为箭头没有自己的 this、arguments 或 [如果相关] super)。所以理论上,它的重量更轻。反驳这是一些可读性问题——“我没有意识到这是一个函数”(尽管我怀疑人们会习惯箭头函数)——function 声明的提升行为有时是有用且没有箭头类似物。
² “function 声明总是包含一个名称(有一个模糊的例外²)。” 模糊的例外是这样的:
export default function() { }
这是一个导出函数声明,不是函数表达式,有提升等。这是函数声明唯一不能指定名称的地方。 (不过,该函数确实有一个名称:default。)