I recently joined a large software developing project which uses mainly JavaScript and a particular question has been on my mind since day one. I know this issue has been here on SO before, but I have never seen the core question being properly answered. So here I ask it again:
Are there any benefits in JavaScript in using function expressions rather than function declarations?
In other words, is this:
var myFunction = function () {
// Nice code.
}
in any way better than this:
function myFunction () {
// Nice code.
}
As I see it, function expressions only introduce negative aspects on several levels to the code base. Here I list a few.
Function expression as the one above, suddenly forces you to be careful with forward references, as the anonymous function object that the myFunction variable refers to, does not exist until the variable expression actually executes. This is never a problem if you use function declarations.
Apart from generating twice as many objects as in the case with function declarations, this usage introduces a very bad programming habit, which is that developers tend to declare their functions only when they feel they need them. The result is code that mixes object declarations, function expressions and logic in something that obscures the core logic of a piece of code.
As a side effect of 2), code becomes much harder to read. If you would use proper function declarations and only var declarations for objects that actually will be variable in the code, it becomes far easier to scan the indentation line of code segment and quickly find the objects and the functions. When everything is declared as "var", you are suddenly forced to read much more carefully to find this piece of information.
As yet another nasty side effect of 2), as users get into the bad habit of only declaring their functions when they feel they need them, function expressions start showing up inside event handlers and loops, effectively creating a new copy of the function object either each time an event handler is called or for each turn in the loop. Needless to say, this is bad! Here is an example to show what I mean:
var myList = ['A', 'B', 'C'];
myList.forEach(function (element) {
// This is the problem I see.
var myInnerFunction = function () {
// Code that does something with element.
};
};
So to sum up, at least in my view, the only situation in which it is fair to use something like:
var myFunction = function () {
// Nice code.
}
is when your logic intends to change the myFunction reference to point at different functions during execution. In that situation myFunction (the variable) is something that is variable in the code, hence you are properly informing a different programmer of your intents, rather than confusing him/her.
With this background in mind, I ask my question again. Have I missed something central about function expressions (in the context described above) in which they provide any benefit over function declarations?
Related
This question already has answers here:
How to execute a JavaScript function when I have its name as a string
(36 answers)
Closed 8 years ago.
I have a JavaScript variable which contains the name of a JavaScript function. This function exists on the page by having been loaded in and placed using $.ajax, etc.
Can anyone tell me how I would call the javascript function named in the variable, please?
The name of the function is in a variable because the URL used to load the page fragment (which gets inserted into the current page) contains the name of the function to call.
I am open to other suggestions on how to implement this solution.
I'd avoid eval.
To solve this problem, you should know these things about JavaScript.
Functions are first-class objects, so they can be properties of an object (in which case they are called methods) or even elements of arrays.
If you aren't choosing the object a function belongs to, it belongs to the global scope. In the browser, that means you're hanging it on the object named "window," which is where globals live.
Arrays and objects are intimately related. (Rumor is they might even be the result of incest!) You can often substitute using a dot . rather than square brackets [], or vice versa.
Your problem is a result of considering the dot manner of reference rather than the square bracket manner.
So, why not something like,
window["functionName"]();
That's assuming your function lives in the global space. If you've namespaced, then:
myNameSpace["functionName"]();
Avoid eval, and avoid passing a string in to setTimeout and setInterval. I write a lot of JS, and I NEVER need eval. "Needing" eval comes from not knowing the language deeply enough. You need to learn about scoping, context, and syntax. If you're ever stuck with an eval, just ask--you'll learn quickly.
If it´s in the global scope it´s better to use:
function foo()
{
alert('foo');
}
var a = 'foo';
window[a]();
than eval(). Because eval() is evaaaaaal.
Exactly like Nosredna said 40 seconds before me that is >.<
Definitely avoid using eval to do something like this, or you will open yourself to XSS (Cross-Site Scripting) vulnerabilities.
For example, if you were to use the eval solutions proposed here, a nefarious user could send a link to their victim that looked like this:
http://yoursite.com/foo.html?func=function(){alert('Im%20In%20Teh%20Codez');}
And their javascript, not yours, would get executed. This code could do something far worse than just pop up an alert of course; it could steal cookies, send requests to your application, etc.
So, make sure you never eval untrusted code that comes in from user input (and anything on the query string id considered user input). You could take user input as a key that will point to your function, but make sure that you don't execute anything if the string given doesn't match a key in your object. For example:
// set up the possible functions:
var myFuncs = {
func1: function () { alert('Function 1'); },
func2: function () { alert('Function 2'); },
func3: function () { alert('Function 3'); },
func4: function () { alert('Function 4'); },
func5: function () { alert('Function 5'); }
};
// execute the one specified in the 'funcToRun' variable:
myFuncs[funcToRun]();
This will fail if the funcToRun variable doesn't point to anything in the myFuncs object, but it won't execute any code.
This is kinda ugly, but its the first thing that popped in my head. This also should allow you to pass in arguments:
eval('var myfunc = ' + variable); myfunc(args, ...);
If you don't need to pass in arguments this might be simpler.
eval(variable + '();');
Standard dry-code warning applies.
I'm fine with the pure function concept on pretty simple examples like...
function addTwo(val){
return val + 2;
}
Given the same arguments, it yields the same result, leading to Referential Transparency and good deterministic code.
But then I've came across examples like these (taken from professor frisby mostly adequate guide, but I've found similar examples on other FP JS books)
//pure
var signUp = function(Db, Email, attrs) {
return function() {
var user = saveUser(Db, attrs);
welcomeUser(Email, user);
};
};
var saveUser = function(Db, attrs) {
...
};
var welcomeUser = function(Email, user) {
...
};
and I don't get why isn't considered an external dependency (so, impure) the call to saveUser or welcomeUser.
I know that from a function/IO point of view, signUp always return the "same" (an equivalent) wired function, but it feels weird to me.
It's difficult to me to understand why even
function multiplyBy(times){
return value => value * times;
}
const fiveTimes = multiplyBy(5);
fiveTimes(10);
is considered pure. From the returned function POV, accesing to times is a lookup on the scope-chain, it could come from the immediate outer scope, or from beyond (like global scope).
Any one wants to bring some light to this?
My explanation for function purity in JavaScript is that there's no such thing as a binary "pure" or "impure", but rather a spectrum of confidence that a function will behave predictably. There's all kinds of tricks that can be played to make a function that seems pure not be, by passing an object with a side-effect getter on it, for example.
So, once we realize that purity is about degree of confidence, we can then ask, how confident am I that some function will behave the way I expect? If that function references another function, how sure are you that the other function is pure? And, moreover, how sure are you that the identifier that's referencing that other function doesn't / can't get re-assigned to point to some other function you aren't aware of?
I personally code my programs so that I almost never re-define an identifier that's pointing at a function, especially if that function is declared rather than just a function expression. In that way, I feel very confident (say, 99.99%) that if foo(..) calls bar(..), and I'm confident that bar(..) is reliably pure, then foo(..) is also reliably pure, because I know I won't reassign bar(..) to any other function and cause surprising results.
Some people even go so far as to define their function identifiers with const fn = function ... I don't think that helps all that much... it probably would take my confidence level from 99.99% to 99.999%. That doesn't move the needle enough to justify its usage, IMO.
Moreover, on the closure part of your question: if an inner function closes over an outer variable that's still contained in a pure function, and nothing re-assigns that variable, then it's effectively a constant, so my level of confidence is very high in the predictability.
But again, the take away is that function purity in JS is about level of confidence, not an absolute binary yes or no.
The definition of a pure function is:
A function that does always evaluates the same result value given the same argument value(s) and that does not cause any semantically observable side effect or output, such as mutation of mutable objects or output to I/O devices.
"Having dependencies" plays absolutely no role in defining a pure function. The only thing that matters is whether the function has any side effects and whether its result depends on external state. If a function behaves exactly the same and always produces the same result given the same input, it is pure. If a function has any side effects (modifies global state) or behaves differently depending on external state, it is impure. A function may have a dependency on (read: call) another function as part of its operation; as long as that other function is also pure, that doesn't taint the purity.
The signUp example you show is pure, because it only acts on its input and always returns the exact same output when called with the same input. Note that the function itself doesn't "do" anything. It's not calling the database or produce any side effect. All it does is return a function. But this returned function is always the same if the input is the same. That returned function is in effect impure; but the function that produced it is not.
Are there any limits to what types of values can be set using const in JavaScript, and in particular, functions? Is this valid? Granted it does work, but is it considered bad practice for any reason?
const doSomething = () => {
...
}
Should all functions be defined this way in ES6? It does not seem like this has caught on, if so.
There's no problem with what you've done, but you must remember the difference between function declarations and function expressions.
A function declaration, that is:
function doSomething () {}
Is hoisted entirely to the top of the scope (and like let and const they are block scoped as well).
This means that the following will work:
doSomething() // works!
function doSomething() {}
A function expression, that is:
[const | let | var] = function () {} (or () =>
Is the creation of an anonymous function (function () {}) and the creation of a variable, and then the assignment of that anonymous function to that variable.
So the usual rules around variable hoisting within a scope -- block-scoped variables (let and const) do not hoist as undefined to the top of their block scope.
This means:
if (true) {
doSomething() // will fail
const doSomething = function () {}
}
Will fail since doSomething is not defined. (It will throw a ReferenceError)
If you switch to using var you get your hoisting of the variable, but it will be initialized to undefined so that block of code above will still not work. (This will throw a TypeError since doSomething is not a function at the time you call it)
As far as standard practices go, you should always use the proper tool for the job.
Axel Rauschmayer has a great post on scope and hoisting including es6 semantics: Variables and Scoping in ES6
Although using const to define functions seems like a hack, it comes with some great advantages that make it superior (in my opinion)
It makes the function immutable, so you don't have to worry about that function being changed by some other piece of code.
You can use fat arrow syntax, which is shorter & cleaner.
Using arrow functions takes care of this binding for you.
example with function
// define a function
function add(x, y) { return x + y; }
// use it
console.log(add(1, 2)); // 3
// oops, someone mutated your function
add = function (x, y) { return x - y; };
// now this is not what you expected
console.log(add(1, 2)); // -1
same example with const
// define a function (wow! that is 8 chars shorter)
const add = (x, y) => x + y;
// use it
console.log(add(1, 2)); // 3
// someone tries to mutate the function
add = (x, y) => x - y; // Uncaught TypeError: Assignment to constant variable.
// the intruder fails and your function remains unchanged
It has been three years since this question was asked, but I am just now coming across it. Since this answer is so far down the stack, please allow me to repeat it:
Q: I am interested if there are any limits to what types of values can be
set using const in JavaScript—in particular functions. Is this valid?
Granted it does work, but is it considered bad practice for any
reason?
I was motivated to do some research after observing one prolific JavaScript coder who always uses const statement for functions, even when there is no apparent reason/benefit.
In answer to "is it considered bad practice for any reason?" let me say, IMO, yes it is, or at least, there are advantages to using function statement.
It seems to me that this is largely a matter of preference and style. There are some good arguments presented above, but none so clear as is done in this article:
Constant confusion: why I still use JavaScript function statements by medium.freecodecamp.org/Bill Sourour, JavaScript guru, consultant, and teacher.
I urge everyone to read that article, even if you have already made a decision.
Here's are the main points:
Function statements have two clear advantages over [const] function
expressions:
Advantage #1: Clarity of intent When scanning through
thousands of lines of code a day, it’s useful to be able to figure out
the programmer’s intent as quickly and easily as possible.
Advantage #2: Order of declaration == order of execution
Ideally, I want to declare my code more or less in the order that I
expect it will get executed.
This is the showstopper for me: any value declared using the const
keyword is inaccessible until execution reaches it.
What I’ve just described above forces us to write code that looks
upside down. We have to start with the lowest level function and work
our way up.
My brain doesn’t work that way. I want the context before the details.
Most code is written by humans. So it makes sense that most people’s
order of understanding roughly follows most code’s order of execution.
There are some very important benefits to the use of const and some would say it should be used wherever possible because of how deliberate and indicative it is.
It is, as far as I can tell, the most indicative and predictable declaration of variables in JavaScript, and one of the most useful, BECAUSE of how constrained it is. Why? Because it eliminates some possibilities available to var and let declarations.
What can you infer when you read a const? You know all of the following just by reading the const declaration statement, AND without scanning for other references to that variable:
the value is bound to that variable (although its underlying object is not deeply immutable)
it can’t be accessed outside of its immediately containing block
the binding is never accessed before declaration, because of Temporal Dead Zone (TDZ) rules.
The following quote is from an article arguing the benefits of let and const. It also more directly answers your question about the keyword's constraints/limits:
Constraints such as those offered by let and const are a powerful way of making code easier to understand. Try to accrue as many of these constraints as possible in the code you write. The more declarative constraints that limit what a piece of code could mean, the easier and faster it is for humans to read, parse, and understand a piece of code in the future.
Granted, there’s more rules to a const declaration than to a var declaration: block-scoped, TDZ, assign at declaration, no reassignment. Whereas var statements only signal function scoping. Rule-counting, however, doesn’t offer a lot of insight. It is better to weigh these rules in terms of complexity: does the rule add or subtract complexity? In the case of const, block scoping means a narrower scope than function scoping, TDZ means that we don’t need to scan the scope backwards from the declaration in order to spot usage before declaration, and assignment rules mean that the binding will always preserve the same reference.
The more constrained statements are, the simpler a piece of code becomes. As we add constraints to what a statement might mean, code becomes less unpredictable. This is one of the biggest reasons why statically typed programs are generally easier to read than dynamically typed ones. Static typing places a big constraint on the program writer, but it also places a big constraint on how the program can be interpreted, making its code easier to understand.
With these arguments in mind, it is recommended that you use const where possible, as it’s the statement that gives us the least possibilities to think about.
Source: https://ponyfoo.com/articles/var-let-const
There are special cases where arrow functions just won't do the trick:
If we're changing a method of an external API, and need the object's reference.
If we need to use special keywords that are exclusive to the function expression: arguments, yield, bind etc.
For more information:
Arrow function expression limitations
Example:
I assigned this function as an event handler in the Highcharts API.
It's fired by the library, so the this keyword should match a specific object.
export const handleCrosshairHover = function (proceed, e) {
const axis = this; // axis object
proceed.apply(axis, Array.prototype.slice.call(arguments, 1)); // method arguments
};
With an arrow function, this would match the declaration scope, and we won't have access to the API obj:
export const handleCrosshairHover = (proceed, e) => {
const axis = this; // this = undefined
proceed.apply(axis, Array.prototype.slice.call(arguments, 1)); // compilation error
};
I have being working for a while in javascript and usually do something like this just to cache the value of properties of functions that are declared inside a deep structure or "namespace"
//global scope
(function ($, lib) {
//function scope 1
var format = lib.format, // instead of calling lib.format all the time just call format
touch = lib.pointer.touch, //instead of calling lib.pointer.touch each time just touch
$doc = $(document),
log = logger.log; //not console log...
$doc.on('app:ready', function () {
//function scope 2
$doc.on('some:event', function (e) {
//function scope 3
//use the cached variables
log(format('{0} was triggered on the $doc object', e.type);
});
$doc.on(touch, function (e) {
//function scope 3
log(format('this should be {1} and is... {0} ', e.type, touch);
});
});
}(jQuery, lib));
I was doing that because:
as lazy as I am, writing touch seem more appealing that writing lib.pointer.touch, even when powerful IDEs with fancy autocompletion could help on this, touch is shorter.
a minimizer could convert that single private variable to a single letter variable, so it also made sense for me (I know, I know, never optimize too soon, but this seems to be safe I guess)
All the code written that way seems to perform decently on mobile devices and desktop browsers, so It seems to be a safe practice (In "the practice", pun intended). But I since this relies in closures, and inner functions have to create a closure to save the context it was declared I was wondering...
if a function does not uses variables from the outside context (free variables)... is the closure context still saved? (or if i a tree falls in the wood and nobody is there to hear it, does it still make the crash sound? hehe) I'm aware that this could vary between javascript engines, because ECMA mention nothing about if it is required to save the context or not when variables from the outside are not accessed.
if the above expression is true... will this block of code be more efficient?
//global scope
(function ($, lib) {
//function scope 1
var format = lib.format,
touch = lib.pointer.touch,
$doc = $(document),
log = console.log;
$doc.on('app:ready', function () {
(function ($doc, touch, lib, format) {
// since all the variables are provided as arguments in this function
// there is no need to save them to the [[scope]] of this function
// because they are local to this self invoking function now
$doc.on('some:event', function (e) {
//function scope 3
//use the cached variables
log(format('{0} was triggered on the $doc object', e.type);
});
$doc.on(touch, function (e) {
//function scope 3
log(format('this should be {1} and is... {0} ', e.type, touch);
});
}($doc, touch, lib, format));
});
}(jQuery, lib));
Is it more efficient because it passes those variables to self immediate invoking function? will the cost of creating that new function any impact in the code, (negative or positive)?
How I can properly measure the memory consumption of my javascript library in a reliable way? I have 100x little javascript modules all inside immediate self invoking functions mostly to avoid variables from leaking to the global context. So They all are wrapped in modules very similar to the block of code mentioned above.
will it have a better effect to cache the variables closer, even when that will mean I will have to repeat the declarations of the variables closer to where they're going to be used?
I have the feeling that looking for a variable not in the current local context, the engine will first look into the parent scope and iterate over all the variables at that level... the more variables per level, worse would probably be the performance looking for a variable.
try to find an undefined variable from the internal closures will be the most expensive, because by definition the variable will be first search on the parent scope until the global scope, and not finding it will force the engine to finally reach the global scope. Is that true? are engines optimizing this kind of lookups?
In the end... I know that I will not want to implement my code as the second example mostly because It will make the code harder to read and I'm kinda confortable with the minimized size of the final output using the first approach. My question is motivated by the curiosity and to try to understand a bit better this really nice feature of javascript.
Accordingly to this test...
http://jsperf.com/closures-js
It seems the second approach is faster. But is only evident when iterating an insane number of times... Right now my code does not do that number of iterations... but probably is consuming more memory because of my way of coding...
update: it has being pointed to me that this question is too large. I'm sorry will try to break in small parts. This question was motivated mostly by curiosity as I said, performance seems negligible even in mobile devices. Thank you for all your feedback.
I think it is premature optimization. You already know performance is not a problem in most cases. Even in tight loops, performance does not degrade that bad. Let the JavaScript engine optimize this on its own as Chrome has started doing, by removing unneeded variables from closures.
One important thing is, don't make your code harder to read with unnecessary optimization. Your example takes quite a bit more code, hampering development. In some cases, we are forced to make the code harder to read because we know a particular piece of the app is more memory/performance intensive, but only at that point should we do that.
If you add a breakpoint to the following code (in Chrome), you'll see that the world variable has been optimized out of the closure, look at the 'Closure' node under the Scope Variables http://jsfiddle.net/4J6JP/1/
.
(function(){
var hello = "hello", world="world";
setTimeout(function(){
debugger;
console.log(hello);
});
})()
Note that if you add an eval in that inner function, then all bets are off and the closure can't be optimized.
I followed a little tutorial on Drag & Drop in HTML with Javascript, found here:
http://www.html5rocks.com/tutorials/dnd/basics/
The problem is, I'm working with an in-house style restriction. Meaning all documents have to be written to standards that everyone here uses.
For Javascript, one of them is to always write functions in the object-notation.
I.e.
var myFunction = function() {}
instead of
function myFunction() {}
In this tutorial, the events for the HTML5 drag & drop are added via the addEventHandler() function. This requires you use the normal notation, because if you use the object-notation, the addEventHandler() function trips over it for some reason.
I tried re-writing everything to be like this, without addEventHandler:
myElement.dragstart = function(e) {}
But non of it worked. Using the normal notation with addEventHandler however, everything works like a charm.
I just wanna make sure: am I overlooking something or should this work? Part of me suspects this is just not supported properly yet and you need to use addEventHandler. Is this the case?
Setting the dragstart property vs using addEventHandler('dragstart', ...) is not just a matter of notation. You can and should stick with addEventHandler. There should be no problem, however, using this "style:"
var myFunction = function() {}
myElement.addEventListener('dragstart', myFunction, ...);
Edit
Okay, so this doesn't directly answer the question, but I feel it does need to be addressed in this context.
Writing
var myFunction = function() {}
instead of
function myFunction() {}
is not any sort of "object notation." The first is a function expression, since it's part of an AssignmentExpression. The second is a function declaration. What's the difference? kangax explains it really well:
First of all, function declarations are parsed and evaluated before any other expressions are. Even if declaration is positioned last in a source, it will be evaluated foremost any other expressions contained in a scope.
...
Another important trait of function declarations is that declaring them conditionally is non-standardized and varies across different environments. You should never rely on functions being declared conditionally and use function expressions instead.
Do the people who set the JavaScript code standards in-house really understand the subtle differences?
Point number 1: that's a stupid rule. There are two ways of naming a function for a good reason, and ignoring that to specify one style is fairly dim, IMO.
Your problem is, I think, that your function hasn't been defined by the time you get to addEventHandler. This is because of something called "hoisting". In this process, functions named with the function myFunction() {} syntax are "hoisted" to the top of the function. So if you invoke them anywhere in the function, the function will work. For instance, this will work:
el.addEventListener('click', foo);
function foo() {}
Functions named in your organisation's style, however, are not hoisted. The variable declaration is, but the value is not set until that line of code is reached. So this will not work:
el.addEventListener('click', foo);
var foo = function() {};
The easiest way to get around this would be to move all your function definitions to the top of the scope, unless there is a good reason to define them later. So this will work:
var foo = function() {};
el.addEventListener('click', foo);