spacer spacer spacer

2009-01-16

The difference between `.` and `[` in Javascript

We recently had a bug report that the debugger started issuing a warning in code where it had not before:

 WARNING: reference to undefined property 'length'

The initial fix proposed was to simply change:

 foo.length

to:

 foo.['length']

In Javascript, these two expressions have identical meaning. The second form is normally used if you are trying to access a property whose name is stored in a variable. For instance, to enumerate the properties of an object you can say:

 for (var key in myobject) ... myobject[key] ...

But in LZX script, there is one other subtle difference. When you use . to access a property, if the property does not exist, you will get a warning. If you use [ to access that non-existent property, you don’t. In either case, the value of the expression will be undefined.

We did this because we wanted a way to help users discover type-ohs. We wanted to be able to warn users that they were trying to access a non-existent property — perhaps because the spelled the property incorrectly, or perhaps because the object they were trying to get the property from wasn’t the right object. But we also recognized that there were certain cases where the user needed to test if a property existed or not, without eliciting a warning. There needed to be a way for the user to say “I know what I am doing”[1]. But, if you do this, you really do need to know what you are doing!

As an open source project, OpenLaszlo has lots of people working on it, and sometimes, despite the best intentions, one person working on the code may not fully understand what another person’s code is trying to do. In this case, a well-intentioned change[2] had been mis-applied. A developer who was fixing a dangerous array iteration idiom mistakenly applied it to a value that was an object (being used as a map or hashtable), not an array. Hence the warning about no ‘length’. (They can be forgiven: the code was a doubly-nested loop with no comments and variables with names that gave no clue what they were being used for.)

If we had taken the simple fix — silencing the warning by using the [ operator instead of . — the erroneous iteration would have gone undetected. Eventually, someone would have run into a bug that was a consequence of masking the iteration bug. But it might have been much harder to find then.

There are several lessons to be learned:

1) When you get a warning appearing in code that previously worked, you really want to understand why that warning started showing up all of a sudden. The simplest way of silencing the warning may not be the correct fix.

2) When working on a piece of code you are unfamiliar with, you really need to take the time to understand the code before you make changes.

3) When writing a complex piece of code, use mnemonic names for your variables (local names are ‘free’, you don’t make your code smaller or faster by using short names), and if it’s really tricky code, throw in a comment!


[1] There are a number of other ways to look at object properties, and we used to recommend asking:

 'length' in foo

but in Javascript 2 (and AS3), the in operator only applies to dynamic properties of an object. The in operator does not work on instance properties, e.g.:

 class bar { 
   var zot; 
 } 

 var boo = new bar(); 

 'zot' in boo => false 

 boo.zap = 42 

 'zap' in boo => true

So if you need to make a test for the existence of a property that might be dynamic or might be an instance property, the only way to cover your bases is to use ‘[‘. In the AS3 compiler, you will get an error at compile time if you use . to access a property that the compiler can prove does not exist (because of type inferencing). So the AS3 compiler has adopted the same convention as LZX: If you use ‘[’ to access a property, the compiler assumes you are looking for a dynamic property that may or may not exist at runtime, so it will not issue a warning.

[2] Lots of people take a shortcut in iterating over an array by saying:

 for (var i in myarray) ... myarray[i] ...

But this is dangerous. Because Array’s in Javascript are also Object’s, you can add arbitrary properties to an array. If your loop is only supposed to be looping over the numeric indices of the array, the above loop will break. The correct way to iterate over the elements of an array is:

 for (var i = 0, len = myarray.length; i < len; i++) ... myarray[i] ...

Post a comment

Thanks for signing in, . Now you can comment. (sign out)

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)


Remember me?


You are not signed in. You need to be registered to comment on this site. Sign in