I looked around for how to use the Object.defineProperty
method, but couldn't find anything decent.
Someone gave me this snippet of code:
Object.defineProperty(player, "health", {
get: function () {
return 10 + ( player.level * 15 );
}
})
But I don't understand it. Mainly, the get
is what I can't get (pun intended). How does it work?
Object.defineProperty() is a global function..Its not available inside the function which declares the object otherwise.You'll have to use it statically...
Basically,
defineProperty
is a method that takes in 3 parameters - an object, a property, and a descriptor. What is happening in this particular call is the"health"
property of theplayer
object is getting assigned to 10 plus 15 times that player object's level.Since you asked a similar question, let's take it step by step. It's a bit longer, but it may save you much more time than I have spent on writing this:
Property is an OOP feature designed for clean separation of client code. For example, in some e-shop you might have objects like this:
Then in your client code (the e-shop), you can add discounts to your products:
Later, the e-shop owner might realize that the discount can't be greater than say 80%. Now you need to find EVERY occurence of the discount modification in the client code and add a line
Then the e-shop owner may further change his strategy, like "if the customer is reseller, the maximal discount can be 90%". And you need to do the change on multiple places again plus you need to remember to alter these lines anytime the strategy is changed. This is a bad design. That's why encapsulation is the basic principle of OOP. If the constructor was like this:
Then you can just alter the
getDiscount
(accessor) andsetDiscount
(mutator) methods. The problem is that most of the members behave like common variables, just the discount needs special care here. But good design requires encapsulation of every data member to keep the code extensible. So you need to add lots of code that does nothing. This is also a bad design, a boilerplate antipattern. Sometimes you can't just refactor the fields to methods later (the eshop code may grow large or some third-party code may depend on the old version), so the boilerplate is lesser evil here. But still, it is evil. That's why properties were introduced into many languages. You could keep the original code, just transform the discount member into a property withget
andset
blocks:Note the last but one line: the responsibility for correct discount value was moved from the client code (e-shop definition) to the product definition. The product is responsible for keeping its data members consistent. Good design is (roughly said) if the code works the same way as our thoughts.
So much about properties. But javascript is different from pure Object-oriented languages like C# and codes the features differently:
In C#, transforming fields into properties is a breaking change, so public fields should be coded as Auto-Implemented Properties if your code might be used in separatedly compiled client.
In Javascript, the standard properties (data member with getter and setter described above) are defined by accessor descriptor (in the link you have in your question). Exclusively, you can use data descriptor (so you can't use i.e. value and set on the same property):
Both descriptors can have these members:
for(var i in theObject)
; if false, it will not be iterated, but it is still accessible as public* unless in strict mode - in that case JS stops execution with TypeError unless it is caught in try-catch block
To read these settings, use
Object.getOwnPropertyDescriptor()
.Learn by example:
If you don't wish to allow the client code such cheats, you can restrict the object by three levels of confinement:
Object.isExtensible(<yourObject>)
to check if the method was used on the object. The prevention is shallow (read below).configurable: false
to all properties). UseObject.isSealed(<yourObject>)
to detect this feature on the object. The seal is shallow (read below).writable: false
to all properties with data descriptor). Setter's writable property is not affected (since it doesn't have one). The freeze is shallow: it means that if the property is Object, its properties ARE NOT frozen (if you wish to, you should perform something like "deep freeze", similar to deep copy - cloning). UseObject.isFrozen(<yourObject>)
to detect it.You don't need to bother with this if you write just a few lines fun. But if you want to code a game (as you mentioned in the linked question), you should really care about good design. Try to google something about antipatterns and code smell. It will help you to avoid situations like "Oh, I need to completely rewrite my code again!", it can save you months of despair if you want to code a lot. Good luck.
Summary:
Object.defineProperty
is used in order to make a new property on the player object.Object.defineProperty
is a function which is natively present in the JS runtime environemnt and takes the following arguments:Object.defineProperty(obj, prop, descriptor)
The descriptor object is the interesting part. In here we can define the following things:
<boolean>
: Iftrue
the property descriptor may be changed and the property may be deleted from the object. If configurable isfalse
the descriptor properties which are passed inObject.defineProperty
cannot be changed.<boolean>
: Iftrue
the property may be overwritten using the assignment operator.<boolean>
: Iftrue
the property can be iterated over in afor...in
loop. Also when using theObject.keys
function the key will be present. If the property isfalse
they will not be iterated over using afor..in
loop and not show up when usingObject.keys
.<function>
: A function which is called whenever is the property is required. Instead of giving the direct value this function is called and the returned value is given as the value of the property<function>
: A function which is called whenever is the property is assigned. Instead of setting the direct value this function is called and the returned value is used to set the value of the property.Example:
Defines a new property directly on an object, or modifies an existing property on an object, and return the object.
Simple explanation about define Property.
Example code: https://jsfiddle.net/manoj_antony32/pu5n61fs/
get
is a function that is called when you try to read the valueplayer.health
, like in:It's effectively not much different than:
The opposite of get is set, which would be used when you assign to the value. Since there is no setter, it seems that assigning to the player's health is not intended:
A very simple example: