如何按程序设置 Javascript getter/setter? (或者实际上是闭包范围)

发布于 2024-12-01 22:33:59 字数 850 浏览 4 评论 0原文

我正在尝试按程序向 Javascript 中的对象添加 getter/setter,尽管我认为下面的代码应该可以正常工作,但它并没有按照我的预期运行。

这是我的代码:

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

这是我意想不到的输出,

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

输出对我来说绝对没有意义,但我在 Chrome 和 Webkit 上得到相同的输出,所以我猜我只是愚蠢,这不是 Javascript 的错误引擎:)


正如评论中提到的,我对“数据”的三次使用并不是很好!

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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

可是我不能没有你 2024-12-08 22:33:59

当传递给 __defineGetter__ 的闭包被执行时,循环已完成,key 仍保持在最后一个值。试试这个:

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

其他一些事情:

  1. 您没有在 key 上使用 var,因此 key 是全局的。这并没有导致您的问题,但无论如何添加它是一个好主意。
  2. 当函数范围内已经存在 data 时,您声明了一个名为 data 的新变量。那里不需要使用 var 因为函数中已经有一个 data ;我把它去掉了。
  3. 您没有使用 new,这也会导致奇怪的行为;函数顶部新的三行使其行为就像使用 new 调用一样。

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:

  1. You weren't using var on key, so key was global. That wasn't causing your issue, but it's a good idea to add it anyway.
  2. You were declaring a new variable named data when there was already a data in the scope of the function. It's not needed to use var there since there's already a data in the function; I removed it.
  3. 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 with new.

@罗伯特·古尔德。代码示例中的主要问题不在于“定义 getter 和 setter”,而在于“理解闭包”。

此外,您的代码在使用此内容时无效 关键字,因为您的 Abc() 函数 this 对象指向全局 window 对象。您必须使用 new Abc() 才能正确使用 this 关键字,或者必须在 Abc() 内创建新的空对象并返回它。

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


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

如果您确实需要了解“定义 getters|setters”,请阅读:

@Robert Gould. main problem in your code sample is not in "defining getters and setters", but in "understanding closures".

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:

汐鸠 2024-12-08 22:33:59

key 是 Abc 范围内的局部变量,您编写的匿名函数没有变量 key,因此它使用外部范围中的变量 key。当使用匿名函数时,该变量已更改为循环中的最后一个值,因此您会看到最后一个值。您可以使用闭包来修复此问题:

this.__defineGetter__(key, (function(l_key){
    return function() {
        console.log('using getter');
        return data[l_key];
    }
})(key));

在该代码中,l_key 是匿名函数返回的另一个匿名函数的 key 的本地副本。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文