The loop seems unnecessary but I don't know how to get rid of it.
var a = [
"Start ",
function(){return "middle "},
"end"
],
c = "";
for(var i = 0; i < a.length; i++){
var d = typeof a[i] === 'function' ? a[i]() : a[i];
c = c.concat(d);
}
console.log(c);
var a is generated once at runtime from an array of strings and another array of functions. The functions obviously return dynamic content so doing something like this var a = a[0]+a[1]()+a[2]; by loop once at runtime is not an option since I'd be saving the result of the function and not the function itself.
I've seen some code where a tailor-made function function(){return a[0]+a[1]()+a[2];} is created at runtime that returns the strings and functions() correctly but I don't know how to achieve something like that. In the example I saw the JavaScript source stored in a "string" and editted via String methods and then eval() evaluated. I don't even know if it's worth it in that case.
Join all of those run strings together, then do an eval on the result. May want to add a = null at the end to keep the functions from piling up or...something.
Don't bother optimizing unless you've got actual numbers showing this code is a performance bottleneck. Moreover, eval tends to confuse JavaScript runtimes and defeat the normal optimizations they're able to do, so treat it as a last resort.
So here is a superior FUNCTIONAL version of your code instead.
var a = [
"Start ",
function(){return "middle "},
"end"
],
c = a.map(function(value) {
return typeof value === 'function' ? value() : value;
}).join();
console.log(c);
>>10
This actually reminds me of some Haskell code I've seen... instance (Fractional a) => Fractional (x -> a) where
f / g = liftM2 (/) f g
recip = (recip .)
fromRational = const . fromRational
>>10
this is optimal if all you know is that the array consists of mixed strings and functions that return strings. A routine for concatenating nested arrays of strings can be optimized with a two pass approach, where the first pass calculates the sum of the lengths of all contained strings, allocates a buffer of this length, and then writes all strings to the buffer in a depth first traversal.
JavaScript maps are shit. The only reason for you to use them is to beautify your code. But on average they are slower than a simply for loop like OP's.
I'd speculate that it's because of the extra function call.
I'm not sure if it would apply to >>8 and >>10, but it could also be the allocation of intermediate arrays that can other wise be avoided.
like the difference between:
array.map(f).map(g).map(h)
and
array.map(compose(f,g,h))
Name:
Anonymous2012-05-27 18:38
>>21-22
a simple modification to >>10: String.prototype.call = function(){ return this; };
var a = [
"Start ",
function(){return "middle "},
"end"
],
f = function(x){ return x.call(); },
c = a.map(f).join();
console.log(c);
makes it just as fast as using a for loop: String.prototype.call = function(){ return this; };
var a = [
"Start ",
function(){return "middle "},
"end"
],
c = '';
for(var i = 0; i < a.length; ++i) c += a[i].call();
console.log(c);
for 100000 array elements: map: 56 ms for loop: 52 ms