首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >JS defineProperty与原型

JS defineProperty与原型
EN

Stack Overflow用户
提问于 2012-12-27 00:03:53
回答 6查看 28.9K关注 0票数 35

如您所知,我们可以使用defineProperty()在JS中定义getter和setter。在尝试使用defineProperty()扩展我的类时,我一直被困住了。

下面是一个示例代码:

我有一个必须添加到对象中的字段数组。

代码语言:javascript
复制
fields = ["id", "name", "last_login"]

另外,我还有一个要修改的类。

代码语言:javascript
复制
var User = (function(){
    // constructor
    function User(id, name){
        this.id     = id
        this.name   = name
    }
    return User;
})();

和一个函数,它将使用defineProperty()向类添加字段。

代码语言:javascript
复制
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
            }
        })
    })
};

在运行define_fields()之后,我在User的实例中有我的字段

代码语言:javascript
复制
define_fields(fields);
user1 = new User(1, "Thomas")
user2 = new User(2, "John")

但是这些属性的​​值是相同的。

代码语言:javascript
复制
console.log(user2.id, user2.name) // 2, John
console.log(user1.id, user1.name) // 2, John

在这种情况下,有什么方法可以使defineProperty()正常工作吗?如果我理解了value的问题,那么它对类的每个实例都是相同的,但我无法理解如何修复它。提前谢谢你的回答。

UPD:以这种方式抛出"RangeError:超过最大调用堆栈大小“

代码语言:javascript
复制
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
            }
        })
    })
};
EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2014-10-03 14:48:26

请不要实现任何其他版本,因为它会占用您应用程序中的所有内存:

代码语言:javascript
复制
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

如果实例化了10000个对象:

  • 用我的方法:内存中只有两个函数;
  • 用其它方法: 10000×2= 20000函数;
票数 58
EN

Stack Overflow用户

发布于 2012-12-27 11:18:04

三分钟后,我和Mikhail Kraynov得出了同样的结论。该解决方案在每次调用构造函数时都定义新属性。我想知道,正如您所问的,是否有一种将getter和setter放入原型的方法。以下是我想出的:

代码语言:javascript
复制
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;
}) ();  

在此解决方案中,我在原型中定义字段getter和setter,但在每个实例中引用一个(隐藏)属性,该属性保存字段值。

看这里的小提琴:http://jsfiddle.net/Ca7yq

我在小提琴中添加了更多的代码,以显示对属性枚举的一些影响:http://jsfiddle.net/Ca7yq/1/

票数 18
EN

Stack Overflow用户

发布于 2012-12-27 09:40:21

在我看来,当defineProperties用于prototype时,所有实例都共享该属性。所以正确的变体可能是

代码语言:javascript
复制
var User = (function(){
// constructor
function User(id, name){
    this.id     = id
    this.name   = name

    Object.defineProperty(this, "name", {
        get: function(){ return name },
        set: function(new_value){
            //Some business logic, upperCase, for example
            new_value = new_value.toUpperCase();
            name = new_value
        }
    })
}
return User;
})();
票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14047809

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档