javascript:class.property vs class.prototype.property来模拟静态属性

rij*_*iju 13 javascript static prototype

我一直在尝试在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*/
Run Code Online (Sandbox Code Playgroud)

我的问题#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*/
Run Code Online (Sandbox Code Playgroud)

我的问题#2:我没见过直接使用class.property.javascript中的静态变量究竟是如何记住上面的代码?

或者我在这里编错了什么?这不是正确的看法吗?

T.J*_*der 34

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

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

+=,++和类似的运营商造成的分配,所以他们会导致此行为为好.

考虑:

function Employee() {
}
Employee.prototype.count = 0;
Run Code Online (Sandbox Code Playgroud)

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

+????????????????????+
| Employee.prototype |
+????????????????????+
| count: 0           |
+????????????????????+

然后我们这样做:

var e = new Employee();
Run Code Online (Sandbox Code Playgroud)

现在内存中有第二个对象,它有一个参考Employee.prototype:

+???????????????+
|     e         |
+???????????????+          +????????????????????+
| [[Prototype]] |?????????>| Employee.prototype |
+???????????????+          +????????????????????+
                           | count: 0           |
                           +????????????????????+

如果您查询e.count:

console.log(e.count);
Run Code Online (Sandbox Code Playgroud)

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

但是,当我们这样做时:

e.count += 1; // Or more idiomatically, `++e.count;` or `e.count++;`
Run Code Online (Sandbox Code Playgroud)

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

+???????????????+
|     e         |
+???????????????+
| count: 1      |          +????????????????????+
| [[Prototype]] |?????????>| Employee.prototype |
+???????????????+          +????????????????????+
                           | count: 0           |
                           +????????????????????+

现在,如果您查询e.count:

console.log(e.count);
Run Code Online (Sandbox Code Playgroud)

...引擎找到counte,不看原型.

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

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
Run Code Online (Sandbox Code Playgroud)

这也很有趣:

var e = new Employee();

console.log(e.count);                   // 0
++Employee.prototype.count;
console.log(e.count);                   // 1
Run Code Online (Sandbox Code Playgroud)

既然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`
Run Code Online (Sandbox Code Playgroud)

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;
    })();
    
    Run Code Online (Sandbox Code Playgroud)

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

    然后,这段代码:

    new Employee();
    new Employee();
    new Employee();
    new Employee();
    
    Run Code Online (Sandbox Code Playgroud)

    输出

    1
    2
    3
    4