Javascript ASI and join vs concat(+)
Javascript Automatic Semicolon Insertion
I came across a nice implication of Automatic Semicolon Insertion while developing an API in javascript.
I'll let you guess at first as usual. Try the following
function asi() { var a = 10, b = 20 c = 30; this.log = function () { console.log(a,b,c); }; this.set = function (A,B,C) { a=A; b=B; c=C; } } var a = new asi(); a.log(); var b = new asi(); b.log(); a.set(11,21,31); b.log(); b.set('This', 'is', 'wrong'); a.log();
//Expected output 10 20 30 10 20 30 10 20 30 11 21 31 //What happened?? 10 20 30 10 20 30 10 20 31 11 21 wrong
How Come?
First Thing to note:
See Closely at line 3 there is a comma operator missing. So, now parser will decide what to do :P
Remember:
Whenever a statement misses a semicolon and if the statement following it makes sense along with the former.
Then JS engine will not place a semicolon. Perhaps it parse them as a single statement. [Refer My Prev Post ]
Implication:
var a=10,b=20 remains a incomplete statement without a semicolon
var a=10,b=20c=30; doesn't makeout a valid javascript statement. So ASI makes it var a=10,b=20;c=30; [converse of the above]
Finally:
The variable c is assigned before declaration in the scope of function ASI
Remember:
If a variable is used before declaring it in function scope &&
If the variable is not declared anywhere in the scope chain of the function
Then it will become a property of the Global Scope or the window
Implication:
Hence, variable 'c' is assumed to be declared in the global scope rather in function ASI()
That is all to say about it :)
Better don't save semicolons :P
Use them whenever is needed.
So, that you will be able to trace back errors nicely in case of unintentional errors like the above.
Next is about Join Vs Concat(+)
I was going through many of the test regarding this context @jsperf
I inferred that in all modern browsers (+) for concatenation is optimized in a really nice way [in some cases (+) was 100 times better than join].
But I think the better criteria to choose one among them should be the usecase.
Because both of them will be able to do job in less than a ms
Following is an example why do I feel join is safer than (+)
function whyJoin() { var a, b, c, delim = '&'; return { setter: function (A, B, C) { a = A; b = B; c = C; }, concatMe: function () { return a+delim+b+delim+c; }, joinMe: function () { return [a, b, c].join(delim); } }; } var test = whyJoin(); test.setter('This', 'is', 'Good'); var c = test.concatMe(); var j = test.joinMe(); console.log(c.split('&')); console.log(j.split('&')); test.setter('This', 'is'); c = test.concatMe(); console.log("Doesnt look good", c); j = test.joinMe(); console.log("Seems Fine", j); console.log(c.split('&')); console.log(j.split('&')); test.setter('This', 'is', null); c = test.concatMe(); console.log("Doesnt look good", c); j = test.joinMe(); console.log("Seems Fine", j); console.log(c.split('&')); console.log(j.split('&'));If you had noticed your console following will be the output
["This", "is", "Good"] ["This", "is", "Good"] Doesnt look good This&is&undefined Seems Fine This&is& ["This", "is", "undefined"] ["This", "is", ""] Doesnt look good This&is&null Seems Fine This&is& ["This", "is", "null"] ["This", "is", ""]
Hope you noticed, In Concat(+) undefined or null is converted to their string equivalent and appended which might be undesired in some cases.
Also join keeps things clear & clean.
For ex: If delimiter is going to be the same across all concatenation or operands already exists as an array.
Concat(+) is really useful in many cases
For ex: If the concatenation is not based on some delimiters & number of concatenation operations is less
var result = '
For ex:
for(some condns) { result += [param, param, param].join('&'); }
But Google Optimization suggests creating a string builder for the above case.
function stringBuilder() { this.needls = []; } stringBuilder.prototype.push = function (needle) { this.needls.push(needle); }; stringBuilder.prototype.build = function () { var result = this.needls.join(''); this.needls = []; return result; }; var strBuilderInstance = new stringBuilder(); for(some cdns) { strBuilderInstance.push([param, param, param].join('&')); } var result = strBuilderInstance.build();
All the tests performed in jsperf are performance test :)
Better decide things based on your usecase because javascript is fast enough but the DOM is taking all the time :) -> Douglas Crockford
This is my first time pay a visit at here
ReplyDeleteand i am genuinely impressed to read all at alone
place.
My page > Google optimization
Thank you :)
Delete