【问题标题】:How to Add Static Members in EcmaScript 5如何在 EcmaScript 5 中添加静态成员
【发布时间】:2012-07-27 11:40:41
【问题描述】:

我想在 EcmaScript 5 JavaScript 中的类中添加一个静态函数。我的类定义如下:

var Account = {};

Object.defineProperty(Account, 'id', {
    value : null
});

我会像这样创建一个新实例:

var theAccount = Object.create(Account);
theAccount.id = 123456;

现在我想向Account 类添加一个静态函数。如果我使用构造函数和prototype 属性创建了Account 类,如下所示:

var Account = function () {
    this.id = null;
};

...我可以这样做:

Account.instances = {};

Account.createInstance = function () {
    var account = new Account();
    account.id = uuid.v4();
    Account.instances[account.id] = account;
    return account;
};

但由于我使用Object.defineProperty 而不是prototype 属性来添加成员,所以Account.instancesAccount.createInstance 在调用Object.create 时也会被实例化,因此是实例的属性。

在使用 EcmaScript 5 样式对象创建时如何向类添加静态成员?

【问题讨论】:

  • 问得好、有趣的问题。

标签: javascript ecmascript-5


【解决方案1】:

如果你想要静态方法,对于 ES 5:

// A static method; this method only 
// exists on the class and doesn't exist 
// on child objects
Person.sayName = function() {
    alert("I am a Person object ;)");  
};

// An instance method; 
// All Person objects will have this method
Person.prototype.setName = function(nameIn) {
    this.name = nameIn;  
}

见@https://abdulapopoola.com/2013/03/30/static-and-instance-methods-in-javascript/

【讨论】:

    【解决方案2】:

    你不能。

    我的类定义如下var Account = {};

    那不是一个类(如果我们这样称呼经典模型的话),而只是一个原型对象。由于您只有这些,您需要为静态成员使用其他变量,例如实例缓存或创建函数:

    var Account = {...};
    var instances = [];
    function createAccount(){...}
    

    当然,您可以为它们命名:

    var Account = {
        proto: {...},
        instances: [],
        instantiate: function create(){...}
    };
    

    ...但这看起来非常接近经典模式,不是吗?唯一的区别是你在命名空间对象上有一个create 函数,而不是一个构造函数作为命名空间对象。

    您可能还对问题Object.create Prototype Chains 感兴趣,其中I have discussed 一个完整的继承模型就是这样工作的,createinherit 方法是所有“类对象”都从base 继承的。


    在 cmets 中对您的问题的进一步回答:

    Object.create 不会使 EcmaScript 5 中的 new 运算符过时吗?

    没有。 new keyword 做了两件事:设置新实例的原型链,并应用构造函数。 Object.create 只做第一件事,所以你可以在不需要函数(或不想执行)时使用它。

    在你的情况下,你有这样的功能,所以经典模型在这里也不会错。另见Using "Object.create" instead of "new"

    【讨论】:

    • 谢谢!我想我必须阅读更多关于它的文章才能完全理解每种对象创建方法的作用。这篇文章很有帮助。
    【解决方案3】:

    您似乎混淆了一些不同的东西。原型将是共享的后备属性。如果你想定义一个静态的(我假设你在做什么你的意思是不可写的属性?)你可以在构造函数中使用 defineProperty。

    function Account(){
      Object.defineProperty(this, 'id', {
        value: uuid.v4()
      });
      Account.instances[this.id] = this;
    }
    
    Account.instances = {};
    
    Account.prototype.id = null;
    
    
    var account = new Account;
    

    【讨论】:

    • 谢谢@benvie。但是如果我想使用Object.create 而不是new 创建对象呢? Object.create 不会使 EcmaScript 5 中的 new 运算符过时吗?
    • @MaxKueng - 不,他们做不同的事情。 Object.create() 用于处理声明为对象的“类”(不是真正的类),而 new 用于实例化,它始终是函数,即构造函数。
    • Object.create 用于当您想要创建对象但不初始化它时。如果要初始化它,请使用构造函数,这就是构造函数的重点。 Object.create 甚至在 V8 源代码中使用new 实现。 var obj = new $Object(); obj.__proto__ = proto;github.com/v8/v8/blob/master/src/v8natives.js#L1038
    • @benvie:我认为你不能这么说。它是使用__proto__ 属性实现的,他们也可以使用{} 而不是new $Object();
    • {}new Object 相同,只是它不易被覆盖。这就是我要说的。为了避免它而避免使用new 关键字是没有意义的,没有任何好处。您正在以一种或另一种方式做到这一点。
    【解决方案4】:

    但由于我使用的是 Object.defineProperty 而不是原型 属性来添加成员,Account.instances 和 Account.createInstance 在调用 Object.create 时也会被实例化,因此是 实例的属性。

    在源对象上声明的任何静态属性或方法都不会被视为实例的属性 - 它们将从原型中读取。

        var obj = {};
        obj.static = function() { alert('hello'); }
        var instance = Object.create(obj);
        instance.ownProperty = 'hello';
        alert(!!instance.static); //true - it has .static
        alert(instance.hasOwnProperty('static')); //false - but it's not its own
        alert(instance.hasOwnProperty('ownProperty')); //true
    

    【讨论】:

    • 哇哦!我刚刚了解到!! 会将某些内容转换为布尔值而不否定它。谢谢。从来没有想过这个。
    • 是的,这是一个测试 truthy 值的技巧。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多