【问题标题】:javascript: class.property vs class.prototype.property to emulate static propertiesjavascript:class.property 与 class.prototype.property 模拟静态属性
【发布时间】:2012-11-09 07:15:39
【问题描述】:

我一直在尝试在 javascript 中模拟静态属性。 在几个地方已经提到,class.prototype.property 在从该类继承的所有对象中都是静态的。但我的 POC 另有说法。请看:

使用 Class.prototype.property

//Employee class
function Employee() {
    this.getCount = function(){
        return this.count; 
    };      
    this.count += 1;
}
Employee.prototype.count = 3;

var emp = [], i;
for (i = 0; i < 3; i++) {
    emp[i] = new Employee();
    console.log("employee count is "+ emp[i].getCount());
}
/*Output is:
employee count is 4
employee count is 4
employee count is 4*/

我的问题 #1:如果这是静态的,那么 count 的值不应该是 4、5、6 等,因为所有对象共享相同的 count 变量吗?

然后我用 Class.prototype 做了另一个 POC,我认为这是静态的。

使用 Class.property

//Employee class
function Employee() {
    this.getCount = function(){
        return Employee.count; 
    };      
    Employee.count++;
}
Employee.count = 3;

var emp = [], i;
for (i = 0; i < 3; i++) {
    emp[i] = new Employee();
    console.log("employee count is "+ emp[i].getCount());
}
/*Output is:
employee count is 4
employee count is 5
employee count is 6*/

我的问题 #2:我没有看到直接使用 class.property。记住我上面的代码,javascript中的静态变量究竟是如何制作的?

或者我在这里写错了什么?这不是正确的认识吗?

【问题讨论】:

  • 我一直使用第二种形式。
  • 我认为 this 始终是一个 instance 指向 determine-by-run-time 对象,而 Employee 在您的代码中是一个“原型声明”。

标签: javascript static prototype


【解决方案1】:

我的问题 #1:如果这是静态的,那么 count 的值不应该是 4、5、6 等,因为所有对象共享同一个 count 变量吗?

原型属性在实例之间共享,但如果一个实例有它自己的属性副本,它将使用它。分配给实例上的属性会给它自己的副本,因此它不再使用原型的。

+=++ 和类似的运算符会导致赋值,因此它们也会导致这种行为。

考虑:

function Employee() {
}
Employee.prototype.count = 0;

在上面的代码中,Employee.prototype 的内存中有一个对象。一些 ASCII 艺术:

+−−−−−−−−−−−−−−−−−−−−−+
| Employee.prototype |
+−−−−−−−−−−−−−−−−−−−−−−−+
|计数:0 |
+−−−−−−−−−−−−−−−−−−−−−+

然后我们这样做:

var e = new Employee();

现在内存中有第二个对象,它引用了Employee.prototype

+−−−−−−−−−−−−−−−−+
|电子|
+−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−−−+
| [[原型]] |−−−−−−−−−−>| Employee.prototype |
+−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−−−+
                           |计数:0 |
                           +−−−−−−−−−−−−−−−−−−−−−+

如果你查询e.count:

console.log(e.count);

...由于e 没有自己的名为count 的属性,引擎会查看e 的原型以找到它,找到它并使用该值。

但是,当我们这样做时:

e.count += 1; // Or more idiomatically, `++e.count;` or `e.count++;`

分配一个值给e 实例上的counte 现在拥有自己的 count 副本:

+−−−−−−−−−−−−−−−−+
|电子|
+−−−−−−−−−−−−−−−−−+
|计数:1 | +−−−−−−−−−−−−−−−−−−−−−−−+
| [[原型]] |−−−−−−−−−−>| Employee.prototype |
+−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−−−+
                           |计数:0 |
                           +−−−−−−−−−−−−−−−−−−−−−+

现在如果你查询e.count:

console.log(e.count);

...引擎在e 上找到count,并没有查看原型。

你可以在代码中看到这个效果:

function Employee() {
}
Employee.prototype.count = 0;

var e = new Employee();
console.log(e.hasOwnProperty('count')); // false
e.count += 1;
console.log(e.hasOwnProperty('count')); // true

console.log(e.count);                   // 1
console.log(Employee.prototype.count);  // 0

这也很有趣:

var e = new Employee();

console.log(e.count);                   // 0
++Employee.prototype.count;
console.log(e.count);                   // 1

由于e (还)没有自己的count 副本,如果我们实际增加Employee.prototype 上的属性,无论是直接请求(Employee.prototype.count)还是间接(e.count)。

最后说明:如果e 获得了自己的属性副本,您可以再次将其删除:

var e = new Employee();
console.log(e.count);    // 0, because it's using `Employee.prototype.count`
++e.count;               // Now `e` has its own `count` property
console.log(e.count);    // 1, `e`'s own `count`
delete e.count;          // Now `e` doesn't have a `count` property anymore
console.log(e.count);    // 0, we're back to using `Employee.prototype.count`

delete 更恰当地称为remove。它从对象中删除属性。

我的问题 #2:我没有看到直接使用 class.property。记住我上面的代码,javascript中的静态变量究竟是如何制作的?

两种方式:

  1. 正如你所做的那样,Employee.sharedProperty

  2. 通过在函数内定义整个“类”,并在该函数内使用局部变量:

    var Employee = (function() {
        var sharedVariable = 0;
    
        function Employee() {
            ++sharedVariable;
            console.log("sharedVariable = " + sharedVariable);
        }
    
        return Employee;
    })();
    

    在该外部作用域函数中定义的所有函数都可以访问其中定义的局部变量。所以只有一个变量,在对创建 Employee 的外部函数的一次调用中的局部变量。

    那么,这段代码:

    new Employee();
    new Employee();
    new Employee();
    new Employee();
    

    输出

    1
    2
    3
    4

【讨论】:

  • 感谢您的准确解释。当我看到可以通过 prototoype.properties 在 javascript 中创建静态属性而我的代码不是这样时,我感到非常困惑。
  • 感谢您的准确解释。所以,基本上 Class.prototype.properties 是静态的,在这种情况下只有 object.properties 被更改。如果我改为 Employee.prototype.count +=1 ,那么它会按预期工作。因此,对于确定的静态属性实现,您建议我使用我的第二个代码或您提到的第二种实现方式。再次感谢。
  • @riju:不管怎样,这取决于你。这取决于您希望信息的公开程度。如果你使用Employee.count,而Employee 是公开的,那么Employee.count 是公开的——任何地方的任何代码都可以更新它。这可能很有用。如果您使用模块模式(我的第二个示例),则只有该外部作用域函数中的代码才能访问sharedVariable。实际上,它对您在其中定义的Employee 代码是私有的。您可以将函数添加到Employee.prototype,只要您在作用域函数中这样做,他们就可以使用sharedVariable(但其他人不能)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-25
  • 1970-01-01
  • 2020-12-06
  • 1970-01-01
相关资源
最近更新 更多