Reputation: 18208
I just read through this article on named function expressions and their incompatibilities with IE <= 8.
I'm curious about one statement in particular:
A common pattern in web development is to “fork” function definitions based on some kind of a feature test, allowing for the best performance.
An example taken from his page:
var contains = (function() {
var docEl = document.documentElement;
if (typeof docEl.compareDocumentPosition != 'undefined') {
return function(el, b) {
return (el.compareDocumentPosition(b) & 16) !== 0;
};
}
else if (typeof docEl.contains != 'undefined') {
return function(el, b) {
return el !== b && el.contains(b);
};
}
return function(el, b) {
if (el === b) return false;
while (el != b && (b = b.parentNode) != null);
return el === b;
};
})();
When I see this, my immediate reaction is that this would be terrible to maintain. Code written this way doesn't really lend itself to being easily understandable.
In this case, instead of conditionally defining a function within another function which is then called immediately after the outer function is declared, one could write a function of nested if
s. It would be longer, but in my opinion easier to understand (though I am coming from C/C++/Java).
I would prefer answers that include some test numbers or explanations on how these functions would differ at run time.
Upvotes: 4
Views: 342
Reputation:
Javascript: how much more efficient is forked function declaration?
Barring any magic optimization done with a JIT/run-time it "costs" the same to invoke any function. Functions are just objects that are often stored in variables (or properties).
How much more "efficient" the version that returns a specialized function-object is depends upon factors including (but not limited to):
For a cheap branch or a low number of execution counts the "efficiency" is diminished. If there is a specific use-case, then benchmark that and you will have "the answer".
When I see this, my immediate reaction is that this would be terrible to maintain. Code written this way doesn't really lend itself to being easily understandable.
This example doesn't necessarily do it justice, IMOHO and is messy for other reasons. I think that giving the anonymous outer function an explicit name -- this can be done even for function-expressions -- would help clarify the intent better, for instance. Write code to be clean first. Then run a performance analysis (benchmark) and fix as appropriate. Chance are the "slow parts" won't be what are initially expected.
Some of it "not being easy to understand" is just a lack of familiarity with this construct (not trying to imply anything negative here) -- on the other hand, every language I know of has features which are abused in cases where there are cleaner solutions.
In this case, instead of conditionally defining a function within another function which is then called immediately after the outer function is declared, one could write a function of nested ifs. It would be longer, but in my opinion easier to understand (though I am coming from C/C++/Java).
Again, the exact case is sort of messy, IMOHO. However, JavaScript is not C/C++/Java and functions-as-first-class-values and closures do not exist in C/C++/Java (this is a little white lie, closures can be emulate in Java and the newest C++ supports some form of closures AFAIK -- but I don't use C++).
This construct is thus not seen in those other languages because the other languages do not support it easily (or at all) -- it says nothing about the viability of the approach (in JavaScript or elsewhere) in general.
I would prefer answers that include some test numbers or explanations on how these functions would differ at run time.
See above.
Expanding upon the bold section at top:
A function is "just an object" that is "applied" (read: called) with the (...)
operator.
function x () {
alert("hi")
}
x() // alerts
window.x() // alerts -- just a property (assumes global scope above)
a = {hello: x}
a.hello() // alerts (still property)
b = a.hello
b() // alerts (still just a value that can be invoked)
Happy coding.
Upvotes: 2
Reputation: 100547
This is relatively strange construct if you are coming from pure C background, but should be easily to map to known concepts for C++/Java person. This particular sample is essentially implementation base class with abstract function with 3 derived classes implementing it differently for different browsers. Using "if" or "switch" for such case is not exactly the best approach in either C++ nor Java.
Likely set of such functions will be packaged into a "class" and in such case it will closely map to base class with virtual functions and multiple implementations for each browser...
Upvotes: 0
Reputation: 93674
The main advantage as mentioned is speed. Having a single function with nested if
s means the condition needs to be re-evaluated every time the function is called. However, we know that the results of the conditions will never change.
If you are concerned about readability, a similar effect can be achieved in a more readable way:
var contains = (function () {
var docEl = document.documentElement;
if (typeof docEl.compareDocumentPosition != 'undefined') {
return contains_version1;
} else if (typeof docEl.contains != 'undefined') {
return contains_version2;
} else {
return contains_version3;
}
function contains_version1() {
...
}
function contains_version2() {
...
}
function contains_version3() {
...
}
})();
Or:
(function () {
var docEl = document.documentElement;
var contains =
typeof docEl.compareDocumentPosition != 'undefined' ? contains_version1 :
typeof docEl.contains != 'undefined' ? contains_version2 :
contains_version3;
function contains_version1() {
...
}
function contains_version2() {
...
}
function contains_version3() {
...
}
})();
Upvotes: 1
Reputation: 29658
It is very efficient. Notice the ();
at the very end. This executes and assigns the result of the outer function to contains
immediately. It is much more efficient than executing the underlying logic every time that the function contains
is used.
Instead of checking each time contains()
is called that compareDocumentPosition
exists, this is done once when the code first executes. The fact that compareDocumentPosition
exists or doesn't exist won't change, so only checking it once is ideal.
Upvotes: 3