As you know we can define getters and setters in JS using defineProperty()
. I've been stuck when trying to extend my class using defineProperty()
.
Here is an example code:
I have an array of fields which must be added to a object
fields = ["id", "name", "last_login"]
Also I have a class which will be modified
var User = (function(){ // constructor function User(id, name){ this.id = id this.name = name } return User; })();
And a function which will add fields to the class using defineProperty()
var define_fields = function (fields){ fields.forEach(function(field_name){ var value = null Object.defineProperty(User.prototype, field_name, { get: function(){ return value } set: function(new_value){ /* some business logic goes here */ value = new_value } }) }) };
After running define_fields()
I have my fields in the instance of the User
define_fields(fields); user1 = new User(1, "Thomas") user2 = new User(2, "John")
But the values of these properties are identical
console.log(user2.id, user2.name) // 2, John console.log(user1.id, user1.name) // 2, John
Is there any way to make defineProperty()
work properly in this case? If I understand the problem is with value
which becomes identical for each instance of the class but i can't realise how to fix it. Thanks in advance for your answers.
UPD: This way throws "RangeError: Maximum call stack size exceeded"
var define_fields = function (fields){ fields.forEach(function(field_name){ Object.defineProperty(User.prototype, field_name, { get: function(){ return this[field_name] } set: function(new_value){ /* some business logic goes here */ this[field_name] = new_value } }) }) };
prototype is a property of a Function object. It is the prototype of objects constructed by that function. __proto__ is an internal property of an object, pointing to its prototype. Current standards provide an equivalent Object.
In JavaScript, an object can inherit properties of another object. The object from where the properties are inherited is called the prototype. In short, objects can inherit properties from other objects — the prototypes.
Using getter syntax you create a property which, prior to ES2015, you had to know the name of at the time that you were writing the code. Object. defineProperty allows you to perform the same as the above but, even before ES2015, does not require you to know the name of the property in advanced.
prototype. constructor. The constructor property returns a reference to the Object constructor function that created the instance object. Note that the value of this property is a reference to the function itself, not a string containing the function's name.
Please don't implement any other version because it will eat all your memory in your app:
var Player = function(){this.__gold = 0}; Player.prototype = { get gold(){ return this.__gold * 2; }, set gold(gold){ this.__gold = gold; }, }; var p = new Player(); p.gold = 2; alert(p.gold); // 4
If 10000 objects are instantiated:
I came to the same conclusion as Mikhail Kraynov three minutes after he answered. That solution defines new properties each time the constructor is called. I wondered if, as you asked, there was a way of putting the getters and setters in the prototype. Here is what I came up with:
var User = (function () { function User (id, nam) { Object.defineProperty (this, '__', // Define property for field values { value: {} }); this.id = id; this.nam = nam; } (function define_fields (fields){ fields.forEach (function (field_name) { Object.defineProperty (User.prototype, field_name, { get: function () { return this.__ [field_name]; }, set: function (new_value) { // some business logic goes here this.__[field_name] = new_value; } }); }); }) (fields); return User; }) ();
In this solution I define the field getters and setters in the prototype but reference a (hidden) property in each instance which holds the field values.
See the fiddle here : http://jsfiddle.net/Ca7yq
I added some more code to the fiddle to show some effects on enumeration of properties : http://jsfiddle.net/Ca7yq/1/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With