JavaScript shortcut notations that shouldn’t be black magic to the “average developer”
When publishing articles about JavaScript development you run into many rules set by publishers and editors. This is a great thing as it keeps us authors on our toes and makes us understand more about how much work successful publishing really is. However, it can also be terribly annoying, especially when older idioms just stick. One of them is that “the average developer” does not quite understand JavaScript shortcut notations.
Now, if you are “the average developer”, please give me 5 minutes of your time to get through the following, you’ll understand a lot more code out there and also spend a lot less time writing your own scripts.
Array shortcut notation – It is hip to be square
The first bugbear I have are arrays. These are terribly useful and omnipresent in JavaScript and still I find people who write convoluted things like:
var links = new Array();
links[0] = 'http://cuteoverload.com';
links[1] = 'http://icanhascheezburger.com';
links[2] = 'http://pencilsatdawn.wordpress.com';
links[3] = 'http://apelad.blogspot.com';
// ... ad nauseam ...
This is convoluted (you have to repeat the array name for every item) and also tricky to maintain. When you change the order (granted the order is of importance) you need to change the number, too. It is not necessary, as the numbering is done automatically for you. All you need to do is use the square brackets:
var links = [
'http://cuteoverload.com',
'http://icanhascheezburger.com',
'http://pencilsatdawn.wordpress.com',
'http://apelad.blogspot.com' // <-- last one, NO COMMA!
];
This makes it more obvious from a visual point of view, too. The indentation makes it easy to spy where the array begins and where it ends. Much less line noise to take in.
Notice that you need to separate each item with a comma, but make sure you don’t have a trailing comma at the last item. You can even nest arrays that way:
var links = [
'http://cuteoverload.com',
'http://icanhascheezburger.com',
[100,200,20,'foo'],
'http://pencilsatdawn.wordpress.com',
'http://apelad.blogspot.com' // <-- last one, NO COMMA!
];
On that note, here’s another trick: to add a new item to arrays, you can either use the push() method or use the length property:
links.push('http://dailypuppy.com');
links[links.length] = 'http://bigeyedeer.wordpress.com';
Associative Arrays – OMG! Ponies!
One myth that keeps sticking is that JavaScript has a magical thing called associative arrays. These allow you to not just number the items but give them names instead! You find examples like:
var links = new Array();
links['Cute Overload'] = 'http://cuteoverload.com';
links['I can has cheeseburger'] = 'http://icanhascheezburger.com';
links['Pencils at dawn'] = 'http://pencilsatdawn.wordpress.com';
links['Hobotopia'] = 'http://apelad.blogspot.com';
This is treachery to the highest degree. It is a confusing JavaScript trait, as what you created here is not really an array, but an object. Want proof? – Do an alert(typeof links) or try alert(links[1]).
Object shortcut (literal) notation – getting curly.
So called associative arrays are actually objects, which means you will also find other scripts that took the earlier example serious and use the following instead:
var links = new Object();
links['Cute Overload'] = 'http://cuteoverload.com';
links['I can has cheeseburger'] = 'http://icanhascheezburger.com';
links['Pencils at dawn'] = 'http://pencilsatdawn.wordpress.com';
links['Hobotopia'] = 'http://apelad.blogspot.com';
Again we have far too much repetition. For objects, you have the Object Literal Notation as a shortcut, which basically is using curly braces:
var links = {
'Cute Overload' : 'http://cuteoverload.com',
'I can has cheeseburger' : 'http://icanhascheezburger.com',
'Pencils at dawn' : 'http://pencilsatdawn.wordpress.com',
'Hobotopia' : 'http://apelad.blogspot.com' // <-- again, no comma!
}
The semicolons get replaced by commatacommas (Happy, Stuart?) (except for the last one which you need to omit) and the equal signs become colons. If the properties (the things to the left of the colon) don’t have any spaces in them, you can even get rid of the quotes:
var chris = {
hair : 'red',
age : 32,
city : 'London'
}
You can access the properties with object.property when they don’t have any spaces or with object[property] when they have spaces. For example:
var links = {
'Cute Overload' : 'http://cuteoverload.com',
'I can has cheeseburger' : 'http://icanhascheezburger.com',
'Pencils at dawn' : 'http://pencilsatdawn.wordpress.com',
'Hobotopia' : 'http://apelad.blogspot.com' // <-- again, no comma!
};
alert(links['I can has cheeseburger']);
alert(links.Hobotopia);
Simple if-else statements – ask and define with the ternary notation
You can shorten simple if statements dramatically. With simple I mean an if statement that assigns one of two values like this:
var YUIguy;
if(city === ‘London’){
YUIguy = ‘Chris’;
} else {
YUIguy = ‘Eric’;
};
Again, a lot of repetition there. The ternary notation works around that problem:
var YUIguy = city === ‘London’ ? ‘Chris’ : ‘Eric’;
A lot of equal signs there. Maybe some parenthesis will make it clearer:
var YUIguy = (city === ‘London’) ? ‘Chris’ : ‘Eric’;
What’s going on here? You define the variable YUIguy and assign it a value. Then you have a statement, in this case the comparison of the variable city and if it equals to the string London (=== tests for both the value and the type, much safer than ==).
Then you ask the question if that is true or not by using the question mark. The option on the left of the colon is the answer to the question when the condition was met and the option on the right of the colon is the answer when the condition was not met. Any condition that could be true or false can go inside the parenthesis.
var direction = (x < max) ? 'left' : 'right';
Offering a fallback option with the default operator
The last thing I wanted to quickly talk about is the double pipe (||) default operator. This one is terribly useful when you want to make sure that something is set with a default value. The following construct is something that should not show up any longer:
var section = document.getElementById('special');
if(!section){
section = document.getElementById('main');
}
Again, useless repetition, as the same can be written as:
var section = document.getElementById('special') || document.getElementById('main');
If the first is not defined, the second gets assigned as a value to section.
Thanks for your time!
I hope this helped “the average developer” to understand how you can make your JS a lot shorter without really cutting down on readability. If you want more detailed information about all these goodies, check out Douglas Crockford’s articles on the matter:
Technorati Tags: javascript, syntax, code, bestpractice, webdevtrick, ternary, default, objectliteral, style, learningjavascript
November 27th, 2007 at 10:59 pm
i'm too lazy to do it myself. can you:
var section = $('special') || $('main') || $('submain') | $('ternarymain');
if, else if, else if, else .... ?
November 27th, 2007 at 11:17 pm
great article!
i find these sort of operator 'tricks' that save typing time and, in many instances, clarify code, can be quite difficult to search for using google, so it's nice to have a little guide to them all wrapped up.
Thanks also for clearing up the array/hash differences -- not coming from the js world, the exact differences involved were previously a bit of a mystery for me.
November 27th, 2007 at 11:42 pm
Nice work. Although the plural of "comma" is "commas", despite how it was originally derived from ancient Greek :)
November 28th, 2007 at 1:42 am
Great! I think these are common pitfalls to people who aren't very experienced with JavaScript, so it's good to have them easy and properly explained.
November 28th, 2007 at 6:02 am
It’s
YUIdude, actually…November 28th, 2007 at 11:10 am
Nice one, Herr Heilmann. Quick question (I could look it up, but why do that when I have a JS Guru available to answer questions? ;-) ):
Where I might previously have used the following to append items to an array:
var myArray = new Array();
myArray[myArray.length] = "something";
myArray[myArray.length] = "something else";
myArray[myArray.length] = "something else again";
What would be the shortcut square-brackety version of appending a new item? Or multiple items at once?
Cheers,
--clive.
November 28th, 2007 at 11:33 am
Nice lineup. You wrote "The last thing I wanted to quickly talk about is the double pipe (||) default operator." Actually, the || operator is just a logical OR operator that has some unusual behavior in JavaScript. The Mozilla documentation describes it as such:
"expr1 || expr2 : Returns expr1 if it can be converted to true; otherwise, returns expr2. Thus, when used with Boolean values, || returns true if either operand is true; if both are false, returns false."
http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Operators:Logical_Operators
The same goes for the && AND operator, btw, which returns expr1 if it evaluates to false and expr2 if it evaluates to false.
November 28th, 2007 at 12:42 pm
Thanks Chris,
You've helped this below average (JS) developer pull herself up by the bootstraps a little! ;-)
November 28th, 2007 at 1:49 pm
This "JSON" notation.
Nothing more.
November 28th, 2007 at 2:25 pm
Just be sure if you are using a library with a dollar function e.g. $('#foo') (e.g.jQuery)
that the library handles IE's buggy implementation of getElementById() otherwise you will be in for a shocker when all of a sudden, some pages on your site/application don't work in IE. :-(
Bug reference:
http://webbugtrack.blogspot.com/2007/08/bug-152-getelementbyid-returns.html
November 28th, 2007 at 4:39 pm
Calling it a "default operator" is misleading. There's nothing special about the "||" operator when used in such a context. The "||" operator is simply a logical "or" operator that is extended to work with non-boolean datatypes. If the left-hand operand resolves to "true" then it is returned, otherwise the right-hand operand is returned. This is exactly the same as the "or" operator in any other language.
November 28th, 2007 at 8:00 pm
Excellent synopsis of good coding practices.
November 29th, 2007 at 12:00 pm
Another note on the double pipe operator – you have to be careful what functions/values/variable you are testing against.
The examples given are very common but the effect on ‘section’ can vary slightly depending on the statements being assigned and this should be noted if you use the value in a boolean test, or are re-factoring existing code.
The example ’!section’ test is relying on ‘null’ and ‘undefined’ evaluating to ‘false’, or as Crockford describes it objects being ‘truthy’.
However this does not allow you to distinguish between an explicit ‘false’ and ‘undefined’.
typeof section;
undefined
var section;
typeof section;
undefined
var section = false;
typeof section;
boolean
// neither element exists
var section = document.getElementById('special') || document.getElementById('main');
typeof section
object
November 29th, 2007 at 12:51 pm
I have a question:
How would one go to iterate through this array (object):
var chris = {
hair : 'red',
age : 32,
city : 'London'
friends : [{
fred: {[hair: 'black',age:35,city:'London']},
steeve: {[hair: 'brown',age:31,city:'London']},
}]
}
November 29th, 2007 at 2:07 pm
@iljmez, what’s with all the arrays?
November 29th, 2007 at 4:24 pm
“You can access the properties with object.property when they don’t have any spaces or with object[property] when they have spaces.”
Not quite. The key has to be a valid identifier to be used in a hash literal without quotes, not just have no spaces. You couldn’t say:
var foo = {
whats.up : ‘asdf’
};
You’d still have to quote the ‘whats.up’.
But that’s a minor quibble. Good post!
November 29th, 2007 at 4:57 pm
These are great tips. The funny thing is that I learned to use them in Javascript AFTER using them in Actionscript (Flash) because AS and JS both use the ECMAScript standard.
November 29th, 2007 at 5:51 pm
Wally,
I didn't understand the last single pipe '|' in your statement!?
>var section = $(‘special’) || $(‘main’) || $(‘submain’) | $(‘ternarymain’);
November 29th, 2007 at 7:46 pm
@cypher: This is from Crockford (read the end of the article), so is JSON, he designed JSON on these ideas. Personally my first exposure to this was via JSON, and working with it frequently makes for a deeper understanding of the principals. But it was confusing at first and this simple explanation is a gateway to getting to JSON.
@iljmez & @Chris: Indexed Arrays can be handy, particularly when you quickly need the length of items. The challenging part I saw in these examples was the nested nature of the data. It is possible to use references within an indexed array that can be utilized programmatically. Consider that chris.hair and [“chris.hair”] are the same thing but myArry1 = [chris.friends.fred,chris.friends.steeve] and myArry2 = [“chris.friends.fred”,”chris.friends.steeve”] are not (an array of objects vs and array of strings). What is interesting though is that chris.friends.fred and [myArry2[0]] are equal! Expanding on this idea, here is an alternate approach:
November 29th, 2007 at 8:24 pm
@Chris: the code in that last comment got fairly muddled by character stripping/replacing. Apologies to all if it does make any sense anymore....
November 29th, 2007 at 8:30 pm
You write:
> If the properties (the things to the left of the colon) don’t
> have any spaces in them, you can even get rid of the quotes:
and then have an example only using quoted strings not containing spaces... ;-)
November 29th, 2007 at 11:13 pm
@Chris: Or, shortened to obscurity:
function loopproperties(o){
for(i in o)
i + ':' + (typeof o[i]!== 'object') ? o[i] : loopproperties(o[i]) + 'n';
};
console.log(loopproperties(o));
November 30th, 2007 at 9:58 am
aka "syntactic sugar"
November 30th, 2007 at 8:48 pm
@Milo: you said
"... If the left-hand operand resolves to “true” then it is returned, otherwise the right-hand operand is returned. This is exactly the same as the “or” operator in any other language."
Sorry, but not all languages work that way. For example, some languages will evaluate BOTH sides of an OR operator before checking to see if at least one of them has evaluated to true. (If memory serves, VB works that way.)
For many programming tasks, it doesn't matter whether the OR operator evaluates both operands first, or just the left one first. However, there are some situations where is does matter, and there are (increasingly common) JS idioms that depend on this 'short-circuit' behavior.
I'm also skeptical of the idea that OR operators in all languages return one of their operands (when neither of them evaluate to false). I believe that some languages return a Boolean value in that case.
My apologies if the above comes across as pedantic, but I believe that this (seemingly subtle) bit of behavior actually is something experience Programmers care about. Personally, I know that whenever I am learning a new language I always check to see if the OR operator supports 'short-circuit' evaluation (or not).
December 5th, 2007 at 1:51 pm
&& operator "Progressive And" is nice too.
I use it for my de&&bug( "http://virteal.com/DebugDarling");
December 5th, 2007 at 11:54 pm
- "The semicolons get replaced by commas (except for the last one which you need to omit)"
And I'll add that if you forget to remove the last one, the whole script is just silently ignored by Internet Explorer.
- About the "assoative arrays really are objects": the best of it is that it's exactly the same with ActionScript. :-)
- About the ternary expression: my view is that it's just less maintenable code in the long run...