0

I have this code:

var properties = ["name", "sex", "location"];
o={};
for (var i=0, l=properties.length; i<l; i++) {
    Object.defineProperty(o, properties[i],{
        get: function () {return "hello";},
        set: function(val){
            console.log(properties[i] + ' is being set');
        },
        enumerable: true,
        configurable: true
    });     
}

o.name = "something";
console.log(o.name);

It seems I can not use defineProperty to define setters and getters dynamicaly from a list because I need to write the body of the get function like:

return name; 

and in the body of the set function

name = val;

so that the code works. If i write something like

this[properties[i]] = val;

or

o[properties[i]]=val;

i end up in an infinite loop, my problem is I only have the name of the property as a string. Is eval() the only solution?

Does any of you know if it is possible to make this thing work. I did some research before and couldn't find any workaround.

Thank you in advance.

I complete my question here with something because someone wrote this: "What u r trying to make is the action property. U can't set any value to these action properties. So u need to make another data properties to hold the corresponding data. e.g. -"

I know I can use other properties to hold the values but I want my code to run as if I would have defined them 1 by 1 like without having to store the values in other properties/variables, its stange to me that i can define them 1 by 1 and it works and when I try to define them dynamical I can't without extra properties/ variables in closures etc:

    Object.defineProperty(o, "name",{
        get: function () {return name;},
        set: function(val){
            name = val;
        },
        enumerable: true,
        configurable: true
    }); 

    Object.defineProperty(o, "sex",{
        get: function () {return sex;},
        set: function(val){
            sex = val;
        },
        enumerable: true,
        configurable: true
    }); 

    Object.defineProperty(o, "location",{
        get: function () {return location;},
        set: function(val){
            location = val;
        },
        enumerable: true,
        configurable: true
    }); 

Ok Guys and Girls I finally understood whats happening. The variables name, sex and location as I used them in the 1 by 1 definition were variable locations(properties defined on the window object and that's the only reason why the code worked I am clear now in my mind about the fact that I have to allocate memory to store the values somewhere else as you all explained that to me else it won't work at all, the best place imho is in a closure so that the values are private. It took me some time to understand that javascript does not have any internal value(place) when you are using a setter function and a getter function to hold that value the property is just bound to that accessor or descriptor object you set and uses that for further calculations.

Thank you all.

Noooooob
  • 91
  • 5
  • Can you elaborate how exactly you end up in an infinite loop trying to access `this[properties[i]]`? Is that perhaps just a problem with the value of `i`, regarding closures? https://stackoverflow.com/q/750486/10955263 – 04FS Feb 08 '19 at 11:46
  • Its not because any problem with i its because the set function will be called again and again every time you set the property inside the set function so its because of recursion. – Noooooob Feb 08 '19 at 11:56
  • Maybe this script couls help? https://gist.github.com/patrickgalbraith/9538b85546b4e3841864 – Cat Feb 08 '19 at 11:58
  • It's the same solution as amedina gave to store the values in some separate variables. – Noooooob Feb 08 '19 at 12:02

3 Answers3

0

How about doing something like this:

    var properties = ["name", "sex", "location"];

    o = {
      state: {} // Saves the value of those properties dynamically.
    };

    for (var i = 0, l = properties.length; i < l; i++) {
      Object.defineProperty(o, properties[i], {
        get: function() {
          return this.state[properties[i]];
        },
        set: function(val) {
          this.state[properties[i]] = val;
          console.log(this.state[properties[i]]);
        },
        enumerable: true,
        configurable: true
      });
    }

    o.name = "something";
    console.log(o.name);

You need some place to save those properties, but you don't know it in advance, so I declared a kind of dictionary that holds the value of each property dynamically.

amedina
  • 2,838
  • 3
  • 19
  • 40
0

You could wrap the private values with an IIFE:

var properties = ["name", "sex", "location"];
var o = {};

for (var i = 0, l = properties.length; i < l; i++) {
  (function (prop) {
    var _val;

    Object.defineProperty(o, prop, {
      get: function () {
        return _val;
      },
      set: function (val) {
        _val = val;
      },
      enumerable: true,
        configurable: true
      });
  })(properties[i]);
}

o.name = "something";
console.log(o.name);
Yom T.
  • 8,760
  • 2
  • 32
  • 49
-1

What u r trying to make is the action property. U can't set any value to these action properties. So u need to make another data properties to hold the corresponding data. e.g. -

var properties = ["name", "sex", "location"];
o={};
for (var i=0, l=properties.length; i<l; i++) {
    Object.defineProperty(o, properties[i],{
        get: function () {return this["_"+properties[i]];},
        set: function(val){
            this["_"+properties[i]] = val;
        },
        enumerable: true,
        configurable: true
    });     
}

o.name = "something";
console.log(o.name);
RK_15
  • 929
  • 5
  • 11