2

I'm trying to create an object that builds its own getters and setters dynamically:

function Person( properties ) { // 'properties' is an object literal

    this._private = properties; // private by convention

    for ( key in this._private ) {

        this[key] = function() {

            return this._private[key];
        }
    }
}

I hoped, this would create something like this:

var jack = new Person({

    working:true,
    age:33,
    gender:'male'
});

jack.working() --> true
jack.age() --> 33
jack.gender() --> 'male'

The problem is, it always returns 'male', like so:

jack.working() --> 'male'
jack.age() --> 'male'
jack.gender() --> 'male'

What am I missing? Oh, and this is just a proof of concept. I know this is not a perfect solution for creating getters and setters in JavaScript.

Kriem
  • 8,666
  • 16
  • 72
  • 120
  • 2
    I know this is not your question, and you might already be aware, but it would improve the code if you put a 'var' in the for loop, i.e.: for ( var key in this._private ) { ... }. Otherwise the 'key' variable will be created in your global scope (or even worse: any existing variable will be overwritten). – Maate Nov 27 '12 at 20:54
  • @Maate You're absolutely right! – Kriem Nov 27 '12 at 20:57

2 Answers2

7

You've got a classic scoping issue. Create a new function to create scope around key:

function Person(properties) { // 'properties' is an object literal
    var key;

    this._private = properties; // private by convention
    this.buildGetter = function (key) {
        this[key] = function () {
            return this._private[key];
        }
    };
    for (key in this._private) {
        this.buildGetter(key);
    }
}

Example: http://jsfiddle.net/SEujb/

Andrew Whitaker
  • 124,656
  • 32
  • 289
  • 307
3

Everybody says eval is evil, but sometimes it can't be avoided:

function Person( properties ) { // 'properties' is an object literal

    this._private = properties; // private by convention

    for ( key in this._private ) {

        eval("this[key] = function() { return this._private['"+key.toString()+"'];}");
    }
}

jsFiddle: http://jsfiddle.net/pitaj/9sWbe/1/

PitaJ
  • 12,969
  • 6
  • 36
  • 55