Oz123 Oz123 - 5 months ago 14
Javascript Question

Is there any advantage or disadvantage for function expressions inside fuction declaration in JavaScript?

Often I see in JavaScript codes stuff similar to the following:

var numbers = [4, 9, 16, 25];

numbers.forEach(function(item){
console.log(item);
})


While this is OK for understanding, you can also write the code in the following way:

function myFunction(item) {
console.log(item);
}
numbers.forEach(myFunction);


sometimes I see more complicated examples. where declarations
are mixed with a complicated program control, for example:

function readStreamAsJSON(stream, callback) {
var data = "";
stream.on("data", function(chunk) {
data += chunk;
});
stream.on("end", function() {
var result, error;
try { result = JSON.parse(data); }
catch (e) { error = e; }
callback(error, result);
});
stream.on("error", function(error) {
callback(error);
});
}
// taken from http://eloquentjavascript.net/21_skillsharing.html


Besides being shorter on sparing variable is there an advantage for writing my JS code in a way that mixes control of functions with so many definitions?


  • I am not sure the title of the question is the right one. Also note, I realize this question can be closed as opinion based question. However, I don't care about opinions like "the first way is more readable than the other". I want to know if there is a technical difference (like for example with the performance case of
    forEach
    vs
    for loop
    ).


Answer

I believe you're effectively asking if there's any particular reason that you can't write this:

function readStreamAsJSON(stream, callback) {
  var data = "";
  stream.on("data", function(chunk) {
    data += chunk;
  });
  stream.on("end", function() {
    var result, error;
    try { result = JSON.parse(data); }
    catch (e) { error = e; }
    callback(error, result);
  });
  stream.on("error", function(error) {
    callback(error);
  });
}

as

function readStreamAsJSON(stream, callback) {
  function dataHandler(chunk) {
    data += chunk;
  }
  function endHandler() {
    var result, error;
    try { result = JSON.parse(data); }
    catch (e) { error = e; }
    callback(error, result);
  }
  function errorHandler(error) {
    callback(error);
  }
  var data = "";
  stream.on("data", dataHandler);
  stream.on("end", endHandler);
  stream.on("error", errorHandler);
}

E.g., declaring the functions separately from using them.

The answer is no, there isn't, provided you keep them in the same scope as I have above. While there are small technical differences between the two, they end up running the same way. You're free to write whichever you prefer.

Note my point about scope, though. This would NOT be the same:

// NOT THE SAME, WILL NOT WORK
function streamDataHandler(chunk) {
  data += chunk;
}
function streamEndHandler() {
  var result, error;
  try { result = JSON.parse(data); }
  catch (e) { error = e; }
  callback(error, result);
}
function streamErrorHandler(error) {
  callback(error);
}
function readStreamAsJSON(stream, callback) {
  var data = "";
  stream.on("data", streamDataHandler);
  stream.on("end", streamEndHandler);
  stream.on("error", streamErrorHandler);
}

The reason that won't work is that you'll have only one version of those functions, and they won't close over the data and callback values passed into readStreamAsJSON.

Also note that function declarations must be at global scope or at the top level of a function. ES2015 enables function statements (which look identical to function declarations) in some other places, but the rules are complex and not yet reliable across JavaScript engines. I'd suggest sticking to declarations at the top level of the function, and for everything else using function expressions.


Brief bit of terminology: There is no function declaration in this code at all:

numbers.forEach(function(item){
    console.log(item);
})

That's a function expression. The semantics are different (declarations happen at a different time, and have different rules).

Comments