JavaScript is an awesome technology. It's really flexible, and allows cool runtime object manipulation, which are not such a headache like in case with Ruby (though that's my personal opinion after working with both).
The common way of properties definition
Well, there are several ways of default properties definition. First one is using object initializer literal. For instance let's have the Car
object:
var Car = {
brand: 'Toyota',
model: 'Prius',
engine: {
state: 'off'
},
turnOn: function() {
this.engine.state = 'on'
console.log('Engine is:', this.engine.state)
}
}
This way object's properties are accessible from the outside world, like:
Car.brand // => "Toyota"
Car.brand = 'Honda'
Car.brand // => "Honda"
Car.engine.state // => "off"
Car.turnOn() // => "Engine is: on"
Car.engine.state // => "on"
And can be changed with values of other type.
Another way of property definition is in the function constructor using this
keyword, which will reference to current Function
object:
function Car() {
this.brand = 'Toyota'
this.model = 'RAV 4'
this.engine = {
state: 'off'
}
}
and they are also accessible from the outside world:
var car = new Car()
car.brand // => "Toyota"
car.brand = 'Honda'
car.brand // => "Honda"
But there are some additional features for property definitions in JavaScript which will be described in next section.
Defining property using Object.defineProperty method
According to documentation, this is a Object
's static method, which takes an object as first parameter, the name of new property as the second parameter, and an object with options. Let's see the next example:
var Car = {
brand: 'Toyota'
}
Object.defineProperty(Car, 'brand', {
writable: false,
})
Car.brand // => "Toyota"
Car.brand = 'BMW'
Car.brand // => "Toyota"
This way, the brand
property can not be overwritten from the outside world. This way, it is possible to set all the aspects of an object property, and gives a good portion of control over the objects' properties. Here are some other options, that should be taken in account:
configurable - has
false
as default, and will allow to change the type of this property or delete the property from this current object if the value will betrue
enumerable - this will indicate if this property should be shown during enumeration, and it will do so only if it's value will be
true
. By default it isfalse
writable -
true
if this property should be changed with an assignment operator=
. Default tofalse
value - it would take any value of any valid, specific type, like number, object, function, etc.
get - this property can take a function as a value and it will override the property value extraction of object through which the property is accessed
set - this property can take a function as a value with a single argument, which can override the logic of assignment operator of object through which the property is accessed.
Let's consider a more complex example. If there is a need to manipulate some other data inside an object, without specific method invocation, it is wise to customise the set
property of object property, as follows:
function CustomGettersSetters() {
var a = null;
var history = [];
Object.defineProperty(this, 'a', {
get() {
console.log('Inside getter')
return a
},
set(arg) {
console.log('Inside setter')
history.push(arg)
a = arg
return true
}
})
this.getHistory = function() { return history }
}
var custom = new CustomGettersSetters();
custom.a // will log "Inside getter" and return `null`
custom.a = '321' // will log "Inside setter", push a value to `history`, and will set value to `a`
custom.a = 764 // will log "Inside setter", push a value to `history`, and will set value to `a`
custom.a // will log "Inside getter" and return `764`
custom.history // will return `undefined`
custom.getHistory() // will return an array ["321", 764]
This way there was added an additional functionality for the current object, without any need for any additional method calls.
Conclusion
The Object.defineProperty
method is a very powerfull tool for object property manipulation, as it allows some sort of control over it, which can be useful at some point. There is also Object.defineProperties
which can create multiple properties in similar way. The difference is that it takes two parameters: first is the object which will have new properties, and second would be an object of properties, which also will contain an object of options mentioned above.
Top comments (3)
Thanks for the post, I've found it very useful.
Found a little mistake in your code. In your initialization, you have:
But everywhere else, you've used (e.g.):
Hey Matej!
I have noticed it, thanks for pointing out! I have added the proper changes, and now it should be fine!
Cheers!
I had no idea you could do so much with
Object.defineProperty
! Really useful info - thanks for the post :)