Javascript - 是一个匿名函数,用作多次创建的回调?

问题描述 投票:1回答:3

当匿名函数作为回调传递给map之类的东西时,函数对象只创建一次或多次?

const newArray = myArray.map(item => item + 100);

如果在一个案例中它只用作回调函数,那么创建命名函数是否有一个好处(调试除外)?

function add100(item) {
  return item + 100;
}
const newArray = myArray.map(add100);
javascript
3个回答
2
投票

该功能仅创建一次。解释器首先必须解析参数列表中的每个项目,然后将每个参数传递给函数 - 每次.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时创建函数。


1
投票

在上面的例子中,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 */ });

一旦添加到窗口,您将永远无法删除事件侦听器。


1
投票

我认为这个问题实际上是错误的

比较这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);
}
© www.soinside.com 2019 - 2024. All rights reserved.