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