See http://jsperf.com/in-vs-member-object-access
Essentially, why is checking if (\'bar\' in foo) {}
significantly slower than if (foo.bar !== und
foo.bar !== undefined
checks just those 2 values to see if they match.
While 'bar' in foo
will have to use some mechanism to loop through the properties of foo
to see if bar
is in it.
Here is an interesting Read from Ecma-script
The in operator
The production RelationalExpression : RelationalExpression in ShiftExpression is evaluated as follows:
1. Evaluate RelationalExpression.
2. Call GetValue(Result(1)).
3. Evaluate ShiftExpression.
4. Call GetValue(Result(3)).
5. If Result(4) is not an object, throw a TypeError exception.
6. Call ToString(Result(2)).
7. Call the [[HasProperty]] method of Result(4) with parameter Result(6).
8. Return Result(7).The Strict Does-not-equal Operator ( !== )
The production EqualityExpression : EqualityExpression !== RelationalExpression is evaluated as follows:
1. Evaluate EqualityExpression.
2. Call GetValue(Result(1)).
3. Evaluate RelationalExpression.
4. Call GetValue(Result(3)).
5. Perform the comparison Result(4) === Result(2). (See below.)
6. If Result(5) is true, return false. Otherwise, return true.
You're right. It makes no sense for "bar" in foo
to be slower than foo.bar
.
The only reason in
isn't just as fast is that it hasn't received as much attention from JIT engineers as the much more common foo.bar
syntax.
Especially in the case in your jsperf test, where the property does exist as a direct property on foo
itself (not a prototype), it stands to reason that 'bar' in foo
shouldn't be any slower than foo.bar !== undefined
. If anything, it should be faster. The main difference between the two is that in
can be answered without even checking the value of the property!
In the foo.bar
case, I expect both the V8 engine and the SpiderMonkey engine will detect that the code isn't doing anything useful (that is, it has no observable effects) and optimize it away entirely. The benchmark isn't measuring any actual work.
Apparently engines are not yet smart enough to optimize away "bar" in foo
, but it's only a matter of time. And priorities.