tags:

views:

98

answers:

2

I have a JavaScript function where someone can pass anything in, and I iterate over each of its keys using the

for x in obj

syntax. However, this results in an error if they pass a primitive (string or number); the correct behavior is for the function to act the same way on those as it would on an object with no keys.

I can do a try..catch block to get around this, but is there another (more succinct) way?

+6  A: 
x && typeof(x) === 'object'

This is true for objects and arrays (though you usually don't want to iterate over arrays with for..in).

EDIT: Fix, per CMS.

Matthew Flaschen
Good test, the only thing I might add is that `typeof` is a unary operator and not a function, so the parens are just making an expression around `x` and then applying the operator. Also, while I'm being pedantic and silly, since `typeof` always returns a string, the `==` operator would likely be a petasecond faster. All that to say, this is totally fine...
Alex Sexton
The only problem can be `null`, is a primitive and `typeof` is unfortunately completely wrong: `typeof null == 'object'`
CMS
Alex: why would `==` be any faster than `===`? According to the ECMAScript spec, exactly the same steps would be performed for both comparisons in this case.
Tim Down
Ah, very elegant. I didn't realize that `typeof` returned `object` for arrays, etc. Thanks!
Trevor Burnham
@Tim: I'm actually not entirely sure, internally why triple equals takes longer in this case. I know, in general triple equals can sometimes be faster, since double-equals often has to do type coercion. All I have are benchmarks though, and I can't really say I'm the best at those, but they're pretty consistent. http://jsbin.com/uveti (you'll have to add a 0 to the end of the iterations variable if you want numbers that aren't too close/small in chrome) - double equals seems to win every time (even if you switch the order). Hope that helps :)
Alex Sexton
Alex: thanks. I only get a significant difference in Firefox. I suspect it's down to optimizations that the compiler can make for that particular benchmark code. For normal use, I still wouldn't expect any difference.
Tim Down
I'm fairly certain that it's not unique to that benchmark code. For Chrome to have significant difference you have to just test longer, it's just really fast. And certainly, in a single check situation, it would be unnoticeable. It's also less bytes across the wire. Call it useless savings, sure, but calling it inaccurate is probably wrong.
Alex Sexton
Here's another benchmark: http://jsbin.com/aruno/4 I've tried to remove some of the possibilities for compiler optimization by comparing different things on each iteration and storing the result of each comparison. In IE and Firefox `===` comes out slightly ahead. Chrome is inconsistent. I wouldn't draw any conclusions about the relative performances of `==` and `===` from this either, except that benchmarks are difficult to get right and not to be trusted.
Tim Down
For that test, the winner is just whichever one you put first. http://jsbin.com/aruno/5 flip it around and '==' wins every time. On the other hand, my test showed consistent results.
Alex Sexton
I did try that earlier and got `===` winning either way round, but none of this really matters much: in a real situation it's very unlikely you'll be doing anything like either of our benchmarks, particularly yours. Code that repeatedly compares the same things is an obvious candidate for compiler optimization, which will change the behaviour. My contention is that in the general case comparing two strings will take the same length of time using either `==` or `===`, and the closeness of the result in my slightly more realistic benchmark would seem to support this.
Tim Down
+2  A: 

There's a number of ways you could infer that, here's a good one:

function isIterable(obj) {
  if (obj && obj.hasOwnProperty) {
    return true;
  }
  return false;
}

You could pick a number of them.

Alex Sexton