当匿名函数作为回调传递给map之类的东西时,函数对象只创建一次或多次?
const newArray = myArray.map(item => item + 100);
如果在一个案例中它只用作回调函数,那么创建命名函数是否有一个好处(调试除外)?
function add100(item) {
return item + 100;
}
const newArray = myArray.map(add100);
该功能仅创建一次。解释器首先必须解析参数列表中的每个项目,然后将每个参数传递给函数 - 每次.map
的内部运行时都不会重新解析参数。 (参数无法使用任何函数重新解析 - 函数无法控制如何调用它。)
const myArray = [1, 2];
const newArray = myArray.map((console.log('argument being parsed'), item => item + 100));
console.log(newArray);
命名函数不仅可用于调试,还可用于可读性。对于像add100
这样微不足道的东西,它可能没有用,但想象一下,如果函数长度为10-20行 - 命名它可能很有用,否则必须查看每一行以确定回调究竟在做什么。即使您没有调试问题,代码可读性(通常)也非常有用。
或者,当然,您可以描述该功能在评论中的作用。
命名函数也可以调用自身,而匿名函数则不能,但在.map
回调中看到这是非常不寻常的。
const arr = [2, 3];
function bigSquare(item) {
const result = item ** 2;
return result < 100
? bigSquare(result)
: result;
}
console.log(arr.map(bigSquare));
解释器只会在尝试解析function
(或=>
)关键字时,或者在调用.bind
时,或者在调用new Function
时创建函数。
在上面的例子中,add100
只创建一次。
function add100(item) {
return item + 100;
}
const newArray = myArray.map(add100);
甚至这个,
const newArray = myArray.map(function add100(item) {
return item + 100;
});
如果在一个案例中它只用作回调函数,那么创建命名函数是否有一个好处(调试除外)?
有!例如,您可以重用该add100
函数。
或者对于另一种情况,假设您要添加一个事件侦听器,并且希望将来稍后将其删除,您将需要该函数对象引用来删除它。
EG
// Add the event listener
window.addEventListener('scroll', add100);
// Remove the event listener
window.removeEventListener('scroll', add100);
以上将工作正常,但如果你这样做;
window.addEventListener('scroll', function add100() { /* do something */ });
window.removeEventListener('scroll', function add100() { /* do something */ });
一旦添加到窗口,您将永远无法删除事件侦听器。
我认为这个问题实际上是错误的
比较这3个案例
function add100(item) {
return item + 100;
}
function doSomethingWithNamedFunction(array) {
return array.map(add100);
}
function doSomethingWithAnonFunction(array) {
return array.map(function(v) { return i + 100; });
}
function doSomethingWithArrowFunction(array) {
return array.map(v => i + 100);
}
const array = [1, 2, 3, 4, 5, 6, 7, 8];
console.log(doSomethingWithNamedFunction(array));
console.log(doSomethingWithNamedFunction(array));
console.log(doSomethingWithNamedFunction(array));
console.log(doSomethingWithAnonFunction(array));
console.log(doSomethingWithAnonFunction(array));
console.log(doSomethingWithAnonFunction(array));
console.log(doSomethingWithArrowFunction(array));
console.log(doSomethingWithArrowFunction(array));
console.log(doSomethingWithArrowFunction(array));
在第一个中,在文件中遇到add100
时创建了一个闭包。每次调用doSomethingWithNamedFunction
时都不会创建与add100相关的新闭包。
在第二种情况下doSomethingWithAnonFunction
每次调用doSomethingWithAnonFunction
时都会创建一个与anon函数相关的闭包
在第三种情况下,doSomethingWithArrowFunction
每次调用doSomethingWithArrowFunction
时都会创建一个与箭头函数相关的闭包。另外,如果this
绑定到anon函数,则为当前值。这是怎么回事取决于JavaScript引擎。最简单的实现将创建一个新函数来包装匿名函数,但我怀疑大多数JavaScript引擎都这样做。
请注意,虽然命名函数与匿名和箭头函数不同。通过在doSomethingWithNamedFunction
中移动命名函数,我们可以获得与命名函数相同的行为
function doSomethingWithNamedFunction(array) {
function add100(item) {
return item + 100;
}
return array.map(add100);
}
现在,即使对于命名的案例,也会创建相同数量的闭包。反之亦然,我们可以将anon函数创建移出其使用范围之外,并使其与原始命名示例相同
const anonFn = function(v) { return i + 100; }
function doSomethingWithAnonFunction(array) {
return array.map(anonFn);
}
const arrowFn = v => i + 100;
function doSomethingWithArrowFunction(array) {
return array.map(arrowFn);
}