Objects as Maps
The point object maps the strings “x” and “y” to the value 0.
The method invocation point.toString() is essentially a lookup of the “toString” property in the object, followed by a function call that sets this to the receiver object and passes in the arguments: (point.toString).apply(point, ). So, we don’t need to adjust our object model to take methods and method invocations into account.
The prototype link of an object can be obtained by calling Object.getPrototypeOf(point), although many browsers also simply represent the prototype link as a regular property of the object with the funny name
point.__proto__ to another object has a very large effect on the subsequent behavior of the
- writable: the property can be updated
- enumerable: the property shows up in for-in loops
- configurable: the property’s attributes can be updated
Property attributes can be queried and updated using the wordy ES5 built-ins Object.getOwnPropertyDescriptor and Object.defineProperty. For example:
This turns “x” into a non-writable, non-configurable property, which is basically like a “final” field in Java. The objects returned by getOwnPropertyDescriptor and passed into defineProperty are collectively called property descriptors, since they describe the properties of objects.
ES5 adds the ability to make objects non-extensible: after calling Object.preventExtensions(point), any attempt to add non-existent properties to the point object will fail. This is sometimes useful to protect objects used as external interfaces from inadvertent modifications by client objects. Once an object is made non-extensible, it will forever remain non-extensible.
ES5 standardized the notion of “getters” and “setters”, i.e. computed properties. For instance, a point whose “y” coordinate is always equal to its “x” coordinate can be defined as follows:
ES5 calls properties implemented using getters/setters accessor properties. By contrast, regular properties are called data properties. This point object has two accessor properties “x” and “y”. The property descriptor for an accessor property has a slightly different layout than that for a data property:
Accessor property descriptors don’t have “value” and “writable” attributes. Instead, they have “get” and “set” attributes pointing to the respective getter/setter functions that are invoked when the property is accessed/updated. If a getter/setter function is missing, the corresponding “get”/”set” attribute is set to undefined. Accessing/updating an accessor property with an undefined getter/setter fails.
- a mapping of strings to data or accessor property descriptors
- a prototype link
- an extensibility flag
This is an accurate model of user-defined ES5 objects.
Implementing your own objects