Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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             }         })     }) }; 
like image 343
nick.skriabin Avatar asked Dec 27 '12 00:12

nick.skriabin


People also ask

What is __ proto __ and prototype?

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.

What is difference between object and prototype in JavaScript?

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.

What is the difference between GET and defineProperty?

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.

What is constructor and prototype in JavaScript?

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.


2 Answers

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:

  • With my method: you will only have 2 functions in the memory;
  • With the other methods: 10000 * 2 = 20000 functions in the memory;
like image 72
Totty.js Avatar answered Oct 05 '22 14:10

Totty.js


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/

like image 38
HBP Avatar answered Oct 05 '22 14:10

HBP