How to procedurally set Javascript getter/setters? (or actually closure scopes)
I'm trying to procedurally add getters/setters to objects in Javascript and although I think the code below should simply work, it doesn't act as I expected.
here is my code:
var data = {a:1, b:2, c:3};
function Abc(data) {
    var data = data || {};
    for ( var key in data ) {
        console.log(key, data[key]);
        this.__defineGetter__(key, function() {
                console.log('using getter');
                return data[key];
            })
    }
    return this;
}
abc = Abc(data);
console.log('this should be 1', abc.a);
console.log('this should be 2', abc.b);
console.log('this should be 3', abc.c);
and this is my unexpected output
a 1
b 2
c 3
using getter
this should be 1 3
using getter
this should be 2 3
using getter
this should be 3 3
the output makes absolutely no sense to me, but I get the same output on Chrome and Webkit, so I'm guessing I'm just stupid and this is not a bug of the Javascript engines :)
as the comments mention my triple开发者_开发技巧 use of "data" isn't really good!
By the time the closure that was passed to __defineGetter__ is executed, the loop has finished and key remains at the last value. Try this:
function Abc(data) {
    if(!(this instanceof Abc)) {
        return new Abc(data);
    }
    data = data || {};
    for(var key in data) {
        (function(key) {
            console.log(key, data[key]);
            this.__defineGetter__(key, function() {
                console.log('using getter');
                return data[key];
            });
        }).call(this, key);
    }
    return this;
}
Some other things:
- You weren't using 
varonkey, sokeywas global. That wasn't causing your issue, but it's a good idea to add it anyway. - You were declaring a new variable named 
datawhen there was already adatain the scope of the function. It's not needed to usevarthere since there's already adatain the function; I removed it. - You weren't using 
new, which was also causing odd behavior; the new three lines at the top of the function cause it to act as if it was called withnew. 
@Robert Gould. main problem in your code sample is not in "defining getters and setters", but in "understanding closures".
- See more about closures in MDN
 
Additionaly your code is invalid on using this keyword, because your Abc() function this object points to global window object. You must use new Abc() to properly use this keyword or must create new empty object inside Abc() and return it.
1)
function Abc(data) {
  data=data||{};
  for(key in data) {
    console.log(key, data[key]);
    (function(data,key) { // defining closure for our getter function 
      this.__defineGetter__(key, function() {
              console.log('using getter');
              return data[key];
            });
    }).call(this,data,key);
  }
  // dont need to return: when used *new* operator *this* is returned by default
}
var abc = new Abc(data);
or 2)
function Abc(data) {
  data=data||{};
  var obj={};
  for(key in data) {
    console.log(key, data[key]);
    (function(data,key) { // defining closure for our getter function 
      obj.__defineGetter__(key, function() {
              console.log('using getter');
              return data[key];
            });
    })(data,key);
  }
  return obj; // return object
}
var abc = Abc(data);
If you realy need to known about "defining getters|setterns" read about:
- Object.defineProperty() MDN and get operator MDN
 - and for back compatibility __defineGetter__ MDN
 - you must also understand what not all top used browsers currently supports getters and setters for properties
 
key is a local variable in the scope of Abc, the anonymous function you wrote has no variable key, so it uses the one from the outer scope. That variable has changed to the last value in the loop by the time the anonymous function is used, so you see the last value. You can fix this with a closure:
this.__defineGetter__(key, (function(l_key){
    return function() {
        console.log('using getter');
        return data[l_key];
    }
})(key));
In that code l_key is a local copy of key to the anonymous function returned be another anonymous function.
 加载中,请稍侯......
      
精彩评论