简体   繁体   中英

Javascript - is an anonymous function used as a callback created multiple times?

When an anonymous function is passed as a callback to something like map, is the function object created only once, or multiple times?

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

Is there a benefit (other than debugging) for creating a named function if it will only be used as a callback in that one case?

function add100(item) {
  return item + 100;
}
const newArray = myArray.map(add100);

The function is only created once. The interpreter first has to parse each item in the argument list, and then each argument is passed to the function - the arguments don't get re-parsed every time .map 's internals run. (the arguments couldn't get re-parsed with any function - a function doesn't control how it gets called.)

 const myArray = [1, 2]; const newArray = myArray.map((console.log('argument being parsed'), item => item + 100)); console.log(newArray); 

A named function is useful not only for debugging, but for readability as well. For something trivial like add100 , it may not be useful, but imagine if the function was 10-20 lines long - naming it could be useful, otherwise one would have to look through each line to figure out what exactly the callback is doing. Even if you're not debugging a problem, code readability is (usually) very useful.

Or, of course, you could describe what the function does in a comment.

A named function can also call itself, whereas an anonymous function can't, but that's very unusual to see in a .map callback.

 const arr = [2, 3]; function bigSquare(item) { const result = item ** 2; return result < 100 ? bigSquare(result) : result; } console.log(arr.map(bigSquare)); 

The interpreter will only create a function while it attempts to parse a function (or => ) keyword, or when .bind is called, or when new Function is called.

In your case above, add100 is only created once.

function add100(item) {
  return item + 100;
}
const newArray = myArray.map(add100);

Or even this,

const newArray = myArray.map(function add100(item) {
  return item + 100;
});

Is there a benefit (other than debugging) for creating a named function if it will only be used as a callback in that one case?

There is! for instance, you can reuse that add100 function.

Or for another case, let's say you want to add an event listener and you want to remove it in later in the future, you will need that function object reference to remove it.

Eg

// Add the event listener
window.addEventListener('scroll', add100);

// Remove the event listener
window.removeEventListener('scroll', add100);

Above will work fine, however if you do this;

window.addEventListener('scroll', function add100() { /* do something */ });
window.removeEventListener('scroll', function add100() { /* do something */ });

You will never be able to remove the event listener that once you added to window.

I think the question is actually mis-leading

Compare these 3 cases

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));

In the first one a closure was created when add100 was encountered in the file. Each time we call doSomethingWithNamedFunction no new closures related to add100 are created.

In the second case doSomethingWithAnonFunction one closure related to the anon function is created each time doSomethingWithAnonFunction is called

In the third case doSomethingWithArrowFunction one closure related to the arrow function is created each time doSomethingWithArrowFunction is called. In addition the current value if this is bound to the the anon function. How that happens is up to the JavaScript engine. The simplest implementation would create a new function to wrap the anonymous function but I doubt most JavaScript engines do that.

Note though the named function is not special vs anonymous and arrow functions. We can get the same behavior with named functions by moving the named function inside doSomethingWithNamedFunction

function doSomethingWithNamedFunction(array) {

  function add100(item) {
    return item + 100;
  }

  return array.map(add100);
}

Now the same number of closures will be created even for the named case. And visa-versa we can move the anon function creation outside its usage and make it the same as the original named example

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);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM