I get that there are possibly three hundred of these questions, and I understand why not to. If we were looping saying a regular for loop, each iteration we are creating an anonymous function expression which is using more memory. Instead we take the function outside of the loop thus giving it a name
Anonymous Function Iteration Example
var elements = document.getElementsByClassName('elementName');
for(var i=0; i < elements.length; i++ )
{
elements[i].addEventListener('click',function(e){
console.log(e);
});
}
Named Function Iteration Example
function handleClickEvents(e) {
console.log(e);
}
var elements = document.getElementsByClassName('elementName');
for(var i=0; i < elements.length; i++ )
{
elements[i].addEventListener('click',handleClickEvents);
}
Problem here is trying to prove someone the logic of this, and to be honest my jsperfs are disproving me completely. Please see the test results for yourself here
So is jsPerf just wrong in the calculations or is this just a myth busted completely? I see that by running the anonymous function as my eventListener function I gain speed compared to the ladder.
Can anyone enlighten me to what the deal is here and why if we gain more speed with the first example should I even bother with two more lines from the second version?
You should not worry about performance-- I hardly imagine you are adding millions of event listeners.
The second alternative (specifying a function reference) is superior in that the function, once defined, could potentially be used in other places. It requires fewer });, and so is less prone to typos. Perhaps more importantly, it is potentially more readable. Let's take the example of passing a function to Array#filter, to check that a filename is a jpg:
names.filter(function(name) {
return /\.jpg$/i.test(name);
});
vs.
function isJpeg(name) { return /\.jpg$/i.test(name); }
names.filter(isJpeg);
If you're chaining methods together, the benefits become more obvious:
names . filter(isJpeg) . map(makeThumbnail) . forEach(uploadJpg);
At the end of the day it doesn't really matter and boils down to personal preference, but the one thing that is clear is that performance concerns should not be what drives your decision, except in very specialized situations. A good general rule is to write very short, one-off functions in-line. With ES6 and arrow functions, more functions can be "very short" and be candidates for inlining.
By the way, even when writing the function in-line, it's often a good idea to give it a name:
names.filter(function isJpeg(name) {
That has a couple of benefits. First, it's a form of documentation/comment and helps people read your code. Second, most debuggers and stack traces will do a better job of reporting about the function. Most minifiers will remove the name so there's no production impact.
I believe there is flaw in your comparison. If you were to reverse the code. Putting the anonymous function later of the comparison. It will be slower. (http://jsperf.com/best-event-listener-practice/5). Later code will always be slower because there has been so many binding has done before.
Related
This is related to, but in my mind not a duplicate of, Passing named arguments to a Javascript function [duplicate] and Named parameters in javascript.
Various answers and comments on those questions propose approaches to deal with the lack of JavaScript language support for named arguments.
The original poster's concern was this:
Calling a Javascript function with something like
someFunction(1, true, 'foo');
is not very clear without familiarity with the function.
Let's say someFunction is declared elsewhere in the code as:
function someFunction(numberOfClowns,wearingHat,screamingAtTopOfLungs) {
console.log(arguments)
}
Is there any particular reason why you couldn't call the function like this?
someFunction(numberOfClowns=1, wearingHat=true,screamingAtTopOfLungs='foo')
From my preliminary testing, this seems to not result in any errors, and certainly addresses any issues of clarity.
I guess you would need to var all of the variables beforehand, and be aware that variable assignment is occurring, so not be too surprised that numberOfClowns is now equal to 1. Anything else that I'm not considering?
Since you're just using the assignments as labels anyway, why not simply use comments?
someFunction(/*numberOfClowns=*/1, /*wearingHat=*/true, /*screamingAtTopOfLungs=*/'foo')
I've seen this done in C code (particularly for functions with 5 or more arguments), and it would avoid the nasty side-effects you mention.
Since there aren't actually any checks being done with the var-assignment version, this seems to have all the same benefits without the downsides.
I guess you would need to var all of the variables beforehand, and be aware that variable assignment is occurring
This is a major problem in my eyes. It makes this a whole more complicated than any of the other approaches, and it's not a local solution - you're polluting your scope.
Anything else that I'm not considering?
The main argument of named parameters/named arguments is that you can order and omit them however you want, and the right values will still end up in the right variables. Your approach does not provide this. Better just use objects as everyone does.
I'd wager there will be more problems than without the assignments.
As you say, assignments return the assigned value, so if the variables are properly declared, there is no problem. To avoid conflicts with other code in the same function, I suggest wrapping the call inside a block, and declaring the parameters with let.
function someFunction(numberOfClowns, wearingHat, screamingAtTopOfLungs) {
console.log(numberOfClowns, wearingHat, screamingAtTopOfLungs);
}
{
let numberOfClowns, wearingHat, screamingAtTopOfLungs;
someFunction(numberOfClowns=1, wearingHat=true, screamingAtTopOfLungs='foo');
}
You may also be interested in destructuring objects:
function someFunction({numberOfClowns, wearingHat, screamingAtTopOfLungs}) {
console.log(numberOfClowns, wearingHat, screamingAtTopOfLungs);
}
someFunction({numberOfClowns: 1, wearingHat: true, screamingAtTopOfLungs: 'foo'});
I'm working through some practice JavaScript problems, and solved a problem involving recursion. Although I got it right, my implementation is different from the "official" solution, so I was wondering if anyone had any insight on whether the official answer is better and if so, why.
Question
Implement a function that takes a function as its first argument, a number num as its second argument, then executes the passed in function num times.
It's ok to use a loop in your implementation, bonus points if you use recursion instead.
My Solution
function repeat(operation, num) {
if (num > 0) {
operation();
repeat(operation, num - 1);
};
};
Given Solution
function repeat(operation, num) {
if (num <= 0)
return;
operation();
return repeat(operation, --num);
};
Is there anything about the given solution that makes it better than mine?
There is a specific reason to directly return the result of a recursive call. This is called "tail recursion", and a clever run-time environment can optimise for that case and execute without using any additional stack space for the recursive calls (it simply reuses the stack space of the current function). In the latest ECMAScipt 6 specification (Javascript to you and me) it specifically calls out that the runtime environment should optimise tail-recursive calls.
In practice, your code does in fact not do anything after the recursive call, so it is properly tail-recursive. Putting the recursive call with a return statement makes it clear that it should be a tail-recursive call, and a bit more likely that the run-time environment will correctly optimise it.
Just bear in the mind. There is something that every JavaScript developer MUST know. If recursion continues very long time the browser can kill your script or alert error to user. Often JavaScript developers uses approaches like this:
var inputArray = [1,2,3,4,5,6];
(function handleArray() {
var currentElement = inputArray.shift();
// do something with currentElement
if (inputArray.length > 0 ) {
setTimeout(handleArray, 0);
}
}());
In this way you will break long time operation on small parts.
The solutions are identical, but in practice the given solution is easier to understand. There is a clear "base case," and the recursion is done in the return statement. Both of these properties lead to better code quality and readability when dealing with recursive functions.
In terms of memory consumption, are these equivalent or do we get a new function instance for every object in the latter?
var f=function(){alert(this.animal);}
var items=[];
for(var i=0;i<10;++i)
{
var item={"animal":"monkey"};
item.alertAnimal=f;
items.push(item);
}
and
var items=[];
for(var i=0;i<10;++i)
{
var item={"animal":"monkey"};
item.alertAnimal=function(){alert(this.animal);};
items.push(item);
}
EDIT
I'm thinking that in order for closure to work correctly, the second instance would indeed create a new function each pass. Is this correct?
You should pefer the first method, since the second one creates a function every time the interpreter passes that line.
Regarding your edit: We are in the same scope all the time, since JavaScript has function scope instead of block scope, so this might be optimizable, but i did not encounter an implementation that doesn't create it every time. I would recommend not to rely on this (probably possible) optimization, since implementations that lack support could likely exceed memory limits if you use this technique extensively (which is bad, since you do not know what implementation will run it, right?).
I am not an expert, but it seems to me that different javascript engines could be handling this in different ways.
For example, V8 has something called hidden classes, which could affect memory consumption when accessing the same property. Maybe somebody can confirm or deny this.
I normally use this pattern to iterate over object properties:
for(var property in object) {
if(object.hasOwnProperty(property)) {
...
}
}
I don't like this excessive indentation and recently it was pointed out to me that I could get rid of it by doing this:
for(var property in object) {
if(!object.hasOwnProperty(property)) {
continue;
}
...
}
I like this because it doesn't introduce the extra level of indentation. Is this pattern alright, or are there better ways?
I personally prefer:
for(var property in object) if(object.hasOwnProperty(property)) {
...
}
There is no extra level of indentation because for, if, etc. will take the next statement if you leave out the curly braces. Since we put all of our code inside the if hasOwnProperty block it makes any braces for the for statement unnecessary.
Essentially it's equivalent to:
for(var property in object) {
if(object.hasOwnProperty(property)) {
...
} else {
continue;
}
}
Syntacticly I'd prefer something like this
function own(obj) {
var ownprops = {};
for (var prop in obj)
if (obj.hasOwnProperty(prop)) ownprops[prop] = 1;
return ownprops;
}
for (var property in own(object)) {
//code
}
Looks nice, but it entails two loops over the same object, not pretty performance wise.
The other way to do it is functionaly
function foreach(obj, func, thisp) {
for (var prop in obj)
if (obj.hasOwnProperty(prop)) func.call(thisp, obj[prop], prop);
}
foreach(object, function(val, key) {
//code
});
Only one loop, but a function is called for every iteration, which is not great performance wise but better than the last solution. Note that it also clobbers the value of this, but you can pass that value explicitly as the optional 3rd argument.
Just some alternatives. The way you are doing it, and the way explained by Daniel is just fine, and without performance compromises.
Also, I'd like to point out that you do not have to indent your code for every single curly brace...
One factor depends on whether you listen to Douglas Crockford. In his book, JavaScript: The Good Parts, he lumps continue in with the bad parts.
"I have never seen a piece of code that was not improved by refactoring it to remove the continue statement." - Douglas Crockford, JavaScript: The Good Parts
As Tim Down mentioned in his comment, Crockford gives no reason in the book to explain why continue should be avoided. But on his website he says, "It tends to obscure the control flow of the function." I only mention Crockford's opinion since many consider him an authority.
Personally I don't see any problem with how you've coded your loop, especially since the continue appears right at the top where it won't easily be overlooked. Are you working with a team of developers? Do they have a good understanding of what continue does? Do you have a code conventions document that talks about how to handle deep nesting of statements?
Mcconnel:
A loop with many breaks may indicate
unclear thinking about the structure
of the loop or its role in the
surrounding code. Excessive breaks
raises often indicates that the loop
could be more clearly expressed as a
series of loops. Use of break
eliminates the possibility of treating
a loop as a black box. Control a
loop's exit condition with one
statement to simplify your loops.
'break' forces the person reading your
code to look inside to understand the
loop's control, making the loop more
difficult to understand.
Dijkstra:
features like break tend to sabotage
the benefits of structured
programming, and prevent the
programmer from understanding the
program as a composition of
independent units
Loops with continue can be factored into this form and thus the loop may be treated as a black box. Crawford is wrong. Breaks smell, but continue is good.
further analysis: http://sites.google.com/site/dustingetz/dev/break-and-continue
As a rule of thumb, which of these methods of writing cross-browser Javascript functions will perform better?
Method 1
function MyFunction()
{
if (document.browserSpecificProperty)
doSomethingWith(document.browserSpecificProperty);
else
doSomethingWith(document.someOtherProperty);
}
Method 2
var MyFunction;
if(document.browserSpecificProperty) {
MyFunction = function() {
doSomethingWith(document.browserSpecificProperty);
};
} else {
MyFunction = function() {
doSomethingWith(document.someOtherProperty);
};
}
Edit: Upvote for all the fine answers so far. I've fixed the function to a more correct syntax.
Couple of points about the answers so far - whilst in the majority of cases it is a fairly pointless performance enhancement, there are a few reasons one might want to still spend some time analyzing the code:
Has to run on
slow computers, mobile devices, old
browsers etc.
Curiosity
Use the same
general principal to performance
enhance other scenarios where the
evaluation of the IF statement does
take some time.
Unless you're doing this a trillion times, it doesn't matter. Go with the one that is more readable and maintainable to you and/or your organization. The productivity gains you will get from writing clean, simple code matters way more than shaving a tenth of a microsecond off your JS execution time.
You should only even start thinking about what performs better when and only when you've written code and it is unacceptably slow. Then you should start tracking down the bottleneck, which will never be something like this. You will never get a measurable performance gain out of switching from one to the other here.
Unfortunately the code above is not actually cross-browser friendly as it relies on a mozilla quirk not present in other browsers -- namely that function statements are treated as function expressions inside branches. On browsers other that aren't built on mozilla the above code will always use the second function definition. I made a simple testcase to demonstrate this here.
Basically the ECMAScript spec says that function statements are treated similarly to var declarations, eg. they all get hoisted to the top of the current execution scope (eg. the start of a <script> tag, the start of a function, or the start of an eval block).
To clarify olliej's answer, your second method is technically a syntax error. You could rewrite it this way:
var MyFunction;
if(document.browserSpecificProperty) {
MyFunction = function() {
doSomethingWith(document.browserSpecificProperty);
};
} else {
MyFunction = function() {
doSomethingWith(document.someOtherProperty);
};
}
Which is at least correct syntax, but note that MyFunction would only be available in the scope in which that occurs. (Omit var MyFunction;, and preferably use window.MyFunction = function() ... for global.)
Technically, I would say that the second one would perform better, because the if statement is only executed once, rather than every time the function is run.
The difference, however, would be negligible to the point of being meaningless. The performance penalty of a single if statement such as this would be insignificant even compared to the performance penalty of simply calling a function. It would make a smallish difference even if if is called a million times.
The first one is easier to understand, because it doesn't have the awkwardness of defining the same function twice based on a condition, with both versions behaving differently. That seems to be a recipe for confusion later on.
I wouldn't be the first person to say that unless you are really insane about this optimization thing, you'll get more of a win out of code readability.
I generally prefer the second version, as the condition only has to be evaluated once and not on every call, but there are times when it's not really feasible because it will hamper readability.
Btw, this is a case where you might want to use the ?: operator, e.g (taken from production code):
var addEvent =
document.addEventListener ? function(type, listener) {
document.addEventListener(type, listener, false);
} :
document.attachEvent ? function(type, listener) {
document.attachEvent('on' + type, listener);
} :
throwError;
For your simplified example I would do what's below assuming that your browser property check only needs to be done once:
var MyFunction = (function() {
var rightProperty = document.browserSpecificProperty || document.someOtherProperty;
return function doSomethingWith() {
// use the rightProperty variable in your function
}
})();
The performance should be nearly equal!
Thing about using Frameworks like JQuery to get rid of the Browser compability problems!
If performance is your main goal, have a look at SlickSpeed! It is a page which benchmarks different JavaScript frameworks!