javascriptprototypedefineproperty

JS defineProperty and prototype


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
            }
        })
    })
};

Solution

  • 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: