Friday, July 11th, 2008

A safety fence for your property lookups

Category: JavaScript, Tip

Michal Till posted a little JavaScript tip that he uses to create a safety fence for accessing properties:

As we all know, null not only does not have any properties, but their existence also can not be tested. So null.property retuns error instead of undefined.

You can end up with something like this:

javascript

  1. if (
  2. (node) &&
  3. (node.nextSibling) &&
  4. (node.nextSibling.className == ...)
  5. ... ) {
  6.    ...

There is a neat trick that can simplify the boolean expression. We might supply an empty object {} or zero (0) as an alternative:

javascript

  1. if ( next = (node || 0).nextSibling) ) {

Posted by Dion Almaer at 6:39 am
12 Comments

+++--
3 rating from 32 votes

12 Comments »

Comments feed TrackBack URI

Nice, this turns the if clause which clearly expresses that the developer expects node or node.nextSibling to possibly be null into an clever/unreadable hack! If only more people properly abused language constructs this way..

Comment by bosmeeuw — July 11, 2008

if (((node || 0).nextSibling || 0).className == 'hello')

if (node && node.nextSibling && node.nextSibling.className == 'hello')

The ‘neat trick’ isn’t that much shorter and a lot less readable! Must agree with bosmeeuw

Comment by philm — July 11, 2008

It is shorter, and I don’t find it unreadable at all. I know right away when I see it that the programmer is trying to guard against a missing attribute.
.
But I don’t think I’d do it (for me, the less parens the better).
.
I do like to see these things, though. Good for the brain.

Comment by Nosredna — July 11, 2008

Also, sometimes these tricks are useful for people writing compilers that target JS as an assembly language. Shorter is usually better in those cases. You might generate the more typical code for debugging and the tighter code for production.
.
Another problem, though, is that the && will shortcut out, so it’s probably faster than the || solution.

Comment by Nosredna — July 11, 2008

Well, unless speed was of the utmost importance, as in a game, wouldn’t this simply be a case where a try/catch block would be much clearer:


try{
if (node.nextSibling.className == "something")
// do something
}
catch(e) {
// catch error
}

Comment by jguide — July 11, 2008

@bosmeeuw, philm:
I think if, upon reading an explanation of what it does, you still find it unreadable, you’re probably doing something wrong.
.
@Nosredna:
I am on the fence; I think the “syntactic sugar” might eventually prove beneficial enough that the parens could become reflex.
.
As for || vs &&, first of all, if that’s your bottleneck, you need to rethink your approach. Second of all, just make sure you use the optimal condition order for your use case.

Comment by eyelidlessness — July 11, 2008

I use This get function:

get=function(hash,arr){
for(var i=0,l=arr.length;i<l;)
if(!hash || (hash=hash[arr[i++]])===undefined )return;
return hash;
}
//And
if(get(node,['nextSi­bling', 'clas­sName'])){
...
}

Comment by linb — July 12, 2008

This has been mentioned before with Oliver Steele’s Maybe Monads on the cheap where he recommends the following maybe monad null propagation behaviour:

(object||{}).property

http://osteele.com/archives/2007/12/cheap-monads

Comment by RichB — July 12, 2008

Thanks your fence!

Comment by KKFC — July 12, 2008

compare :

var r; if(node&&node.nextSibling&&(r=node.nextSibling.className)=='x') return r;
var r; if((r=((node||0).nextSibling||0).className)=='x') return r;

var r; if(r=node)if(r=r.nextSibling)if((r=r.className)=='x') return r;

Using a simple if is maybe a bit longer but faster :-)

Comment by MauriceSchoenmakers — July 13, 2008

heh, so many different ways of accomplishing the same thing :)

@linb: I like your function. One could use a variadic function instead of passing a second parameter as an array for the extra sugar punch (i.e. so the function call looks like get(node, “nextSibling”, “className”) ), though I suspect some people might object with hypothetical performance issues with the body of the function itself.

Comment by LeoHorie — July 14, 2008

@RichB
(object||{}).property is less efficient due to the fact than an anonymous object needs to be created – in a tight loop of hundreds of iterations it will be noticeable.

Comment by matanlurey — July 14, 2008

Leave a comment

You must be logged in to post a comment.