Hi,
I was kind of between doing things when I posted my last answer, so allow me to elaborate, using a simpler example:
As you know, object literals are comma separated lists of key value pairs wrapped in curly braces.
Keys can be strings or identifiers, while values can be any valid expression, including array literals, functions, and nested object literals.
Object literals are used to organise code in a logical fashion and as a means of encapsulating data, so as to avoid polluting the global namespace.
When creating object literals, you can either first create a blank object, then add properties and methods to it.
e.g.
var object = {};
object.foo = 1;
object.bar = null;
object.baz = function() {
console.log("hello from baz()");
};
or create everything up front, as you were doing in your example:
var object = {
foo : 1,
bar : null,
baz : function(){
return "hello from baz()";
}
};
Now, the problem you were encountering, is that using the second notation, the object doesn’t exist until the whole block is interpreted.
This means that referencing a previously declared property from within the object, before the object is created, is problematic.
This works fine:
var object = {}
// object now exists
object.foo = 1;
object.bar = object.foo + 1;
console.log(object.bar);
=> 2
This doesn’t:
var object = {
foo : 1,
bar : object.foo + 1
};
// object now exists
console.log(object.bar);
=> Uncaught TypeError: Cannot read property 'foo' of undefined
When you write object.foo + 1
, object
doesn’t exist at this point.
One way to get around this is to use the aforementioned getter method, thus:
var object = {
foo : 1,
get bar() { return object.foo + 1 }
};
console.log(object.bar);
=> 2
What you are doing here is binding an object property (bar
) to a function that will be called when that property is looked up.
This function will only ever be called after the object exists in memory, so everything works as expected.
By way of further example and to address your second question, we can add a method to our object like this:
var object = {
foo : 1,
get bar() { return object.foo + 1 },
baz : function(){ console.log("hello from baz()"); }
};
object.baz();
=> hello from baz()
Now, say we wanted baz()
to output the value of bar
, then that’s no problem as we have a getter in place:
var object = {
foo : 1,
get bar() { return object.foo + 1 },
baz : function(){ console.log(object.bar); }
};
object.baz();
=> 2
But this getter, doesn’t mean that we can use bar
from within a property declaration:
var object = {
foo : 1,
get bar() { return object.foo + 1 },
foobar : bar + 1
};
object.foobar();
=> Uncaught ReferenceError: bar is not defined
Here, you are still trying to access bar
before the block has been interpreted and the object exists, which won’t work.
If you want to do this, you have to do the same as before and (for example) use a getter method with foobar
var object = {
foo : 1,
get bar() { return object.foo + 1 },
get foobar() { return object.bar + 1}
};
console.log(object.foobar);
=> 3
So, I hope that makes a bit more sense.
I’ve written more than I had intended, so I’ll stop now.