Javascript Square Bracket Notation

Introduction

To be useful javascript needs to be able to access the properties of objects. It is impossible to learn javascript without understanding the dot notation that is normally used to access the properties of objects.

Javascript also offers an alternative property accessor notation using square brackets in a way that is similar to the way in which the indexed members of an Array are accessed, except that a string is used between the square brackets. This alternative notation is extremely powerful and useful but gets very little coverage in most books on javascript and that seems to leave novice javascript programmers unaware that they even have this option.

The coverage in javascript books can be very poor. Looking back at some of the books that I first used to learn javascript, one devotes exactly one paragraph to property accessors and another actually states that the square bracket notation can only be used with integer indexes to access Arrays and array-like structures.

With an understanding of dot notation and few clues that an alternative exists, novice (and a few surprisingly experienced) javascript programmers often turn to the eval function, constructing a string that represents a dot notation accessor (frequently retrieving the property names from javascript variables) and then passing it to the eval function in order to access the object property that it refers to. The eval function is just not needed to perform this type of property access and it is a relatively inefficient way of doing so (plus, some embedded browsers lack the resources to implement an eval function).

Square Bracket Syntax

If you can access the property of an object using dot notation, such as:-

document.body

- you can also use the square bracket notation:-

document['body']

- in which the dot and the identifier to the right of the dot are replaced with a set of square brackets containing a string that represents the identifier that was to the right of the dot.

The Property Accessors section of javascript language specification (ECMA 262) makes it clear that the dot notation and the square bracket notation are parallel ways of accessing the properties of objects.

ECMA 262 3rd Edition. Section 11.2.1 Property Accessors
Properties are accessed by name, using either the dot notation:
MemberExpression.Identifier
CallExpression.Identifier
or the bracket notation:
MemberExpression[ Expression ]
CallExpression[ Expression ]
The dot notation is explained by the following syntactic conversion:
MemberExpression.Identifier
is identical in its behaviour to
MemberExpression[ <identifier-string> ]
and similarly
CallExpression.Identifier
is identical in its behaviour to
CallExpression[ <identifier-string> ]
where <identifier-string> is a string literal containing the same sequence of characters as the Identifier.

In the following simple HTML page:-

<html>
  <head>
    <title></title>
  </head>
  <body>
    <form name="formName" action="#">
      <input type="text" name="inpName" value="Example value text">
    </form>
  </body>
</html>

- which contains a form named "formName" with one input element named "inpName". Various forms of dot notation property accessor can be used to reference the "value" property of the input element. One of the simplest is:-

var stringOfValue = document.formName.inpName.value;

This dot notation has three dots, so there are three points at which the square bracket notation could be used in place of the dot notation (these are all equivalent).

var stringOfValue = document["formName"].inpName.value;

var stringOfValue = document.formName["inpName"].value;

var stringOfValue = document.formName.inpName["value"];

The following combinations are also all equivalent to the original dot notation:-

var stringOfValue = document["formName"].inpName["value"];

var stringOfValue = document["formName"]["inpName"].value;

var stringOfValue = document["formName"]["inpName"]["value"];

var stringOfValue = window["document"]["formName"]["inpName"]["value"];

Where the dot notation follows the dot with the identifier for the property that is to be accessed, the square bracket notation replaces the dot and identifier with square brackets that contain a string that represents the identifier for the property (the property name).

String Variables as Identifiers

The string used within the square brackets does not need to be a string literal. It can be any expression that results in a string. This is where the square bracket notation becomes most useful as the expression could be a reference to a string variable that holds the property name as its value, or a function call that returns a string, or an expression that concatenates two strings, or any combination of these.

This means that the identifier needed to access a property does not need to be coded into a javascript. Consider the following simple function:-

function setPropertyToValue(oObj, sPropName, value){
	oObj[sPropName] = value;
}

- provided with a reference to an object (oObj), the name of a property (sPropName) and a value for that property (value), it will set the value of the property without needing to know what the name of the property that it is setting is. Called as setPropertyToValue(document.formName.inpName, "value", "new value") it will set the value of the field in the example form above to the string "new value". However, called as setPropertyToValue(window, "location", "http://www.google.com") and the same function will navigate a web browser to the URL provided as the final parameter. Although this is a forced example you should be able to see that the square bracket notation offers considerable power and flexibility.

Any variable that holds a string value can be used between the square brackets to form a property accessor. Variables that hold non-strings will have their value internally type converted into a string and that string will be used as the property name. This is not very useful, especially if the variables contain references to objects or functions, as the returned string is likely to be implementation dependent.

String Expressions as Identifiers

The ability to build the string used as the property name can be very useful in loops and with dynamically generating web pages (server side) that have variable length content. The strings can be the result of expressions that concatenate string literals with variables (particularly loop counters).

Given the form:-

<form name="formName" action="#">
	<input type="text" name="field_1">
	<input type="text" name="field_2">
	<input type="text" name="field_3">
</form>

- the following loop will clear the value property of each element it turn:-

for(var c = 1;c < 4;c++){
	document.forms["formName"].elements["field_"+c].value = "";
}

If a server side process had created the HTML form with n elements, named field_1, field_2 ... field_n , then all the server side process would have to do to have the loop clear each and every input element would be to change the 4 in the example to the value of n+1.

Concatenation is the most common type of expression used with the square bracket notation but any javascript expression could be used. A function that returned a string could be used.

In the following (rather contrived) example :-

function getRootElName(){
	if(document.compatMode && (document.compatMode == "CSS1Compat")){
		return "documentElement";
	}else{
		return "body";
	}
}

var verticalScroll = document[getRootElName()].scrollTop;

- the scrollTop value is read from either the document.body or document.documentElement depending on the value of document.compatMode. Passing strings about is far from the best way of achieving what the code above does but there will be circumstances when returning a string from a function call for use in a property accessor is potentially useful.

Global Variable access with the Square Bracket Notation

The square bracket notation requires that there be some sort of object reference to the left of the brackets.

["document"] //Array literal, not a Property Accessor!

-will produce an error if an attempt is made to assign a value to it, as it will be treated as an Array literal, if an attempt to read from it is made the one element array containing the string within the brackets is returned. Global variables are normally referenced by their one identifier alone. This would seem to exclude global variables from the possibility of being referenced using a string that held their identifier name or an expression that built, or returned, their name. However, javascript global variables (and global function names for that matter) are properties of a global object. Any identifier that holds a reference to the global object can be used to the left of the square brackets to form a property accessor that refers to a global variable.

In a web browser the global object is the window (or frame) in which the script is running. Each window (or frame) object contains a number of properties, at least two of which are references to the window (global object) itself. These properties are 'window' and 'self'. These property names can be used as the identifier to the left of the square brackets when referring to global variables. So given a global variable defined as:-

var anyName = 0;

- that global variable can be referenced as:-

window["anyName"]

As with any other use of the square bracket notation, the string within the brackets can be held in a variable or constructed/returned by an expression.

Code that is executing in the global context, the code within global functions (except Object constructors invoked with the new keyword) and inline code outside of any functions, could also use the this keyword to refer to the global object. The this keyword refers to an object depending on the execution context. For code executing in the global context this is the global object (on a web browser, the window object). As a result, the above variable could be referred to as this["anyName"], but only in code that is executing in the global context.

However, using the this keyword is very likely to be confusing, especially in scripts that include custom javascript objects where the methods (and constructors) of those objects would be using this to refer to their own object instances.

Some javascript implementations do not have a property of the global object that refers to the global object. Rather than trying to use the this keyword to access global variables it is possible to create your own global variable that refers to the global object.

var myGlobal = this;

- executed as inline code at the start of a script will assign a reference to the global object (this in that context). From then on all global variables can be referenced with square bracket notation as:-

myGlobal["anyName"];

- and expect myGlobal to refer to the global object from any execution context.

Illegal characters in Identifier-strings

One advantage of the square bracket notation over dot notation is the ability to use characters in identifier-strings that are not legal identifier characters. It is generally best to avoid giving javascript properties names and HTML elements names/IDs that are not made up entirely of characters that are legal in the relevant context. However, it is not always possible to avoid referencing elements with names that include characters that would be illegal in a javascript identifier. PHP offers an example of this, multiple form elements given the same name followed with empty square brackets, such as name="inpEl[]", are made available on the server as an array.

The square bracket notation would allow an element with such a name to be referenced as document.forms["formName"].elements["inpEl[]"][0] for example (the final [0] reflects the fact that multiple elements with the same name, when accessed by name, generate collections of elements and individual elements within that collection need to be referenced by index).

comp.lang.javascript FAQ notes T.O.C.