15

我一直在尝试在 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中的静态变量究竟是如何制作的?

还是我在这里编码错误?这不是正确的认识吗?

4

1 回答 1

38

我的问题 #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++;`

这会在实例上分配一个值。现在有自己的副本:counteecount

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

现在,如果您查询e.count

console.log(e.count);

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

您可以在代码中看到这种效果:

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.counte.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
于 2012-11-21T04:47:25.743 回答