如何使用javascript原型在实例之间共享属性

How are properties shared across instances using javascript prototypes

本文关键字:之间 共享 属性 实例 何使用 javascript 原型      更新时间:2023-09-26

我对原型继承的理解是每个对象都有一个原型属性。如果一个对象的属性不存在,那么它的原型对象就会被检查,以此类推。

在这个例子中,我的原型对象是一个带有counter属性的简单对象。

我希望每个实例共享相同的原型,但他们似乎得到了新的实例。这段代码的输出是00,我期望的是01。

我错过了什么明显的吗?

"use strict";
var ConstructorFunction = function () {};
ConstructorFunction.prototype = {
    counter: 0,
    count: function () {
        return this.counter++;
    }
};
var a = new ConstructorFunction();
var b = new ConstructorFunction();
$("#output").append(a.count());
$("#output").append(b.count());

这里是jsfiddle: http://jsfiddle.net/hdA6G/5/

原型属性在所有实例之间是共享的。问题是你永远不会改变原型属性。看看你的小提琴和一些额外的日志:

"use strict";
var ConstructorFunction = function () {};
ConstructorFunction.prototype = {
    counter: 0,
    count: function () {
        return ++this.counter;
    }
};
var a = new ConstructorFunction();
var b = new ConstructorFunction();
$("#output").append(a.hasOwnProperty("counter") + " "); //false
a.count();
$("#output").append(a.hasOwnProperty("counter") + " "); //true

如您所见,只要您调用++this.counter,就会创建一个本地属性,并从该属性开始使用。

假定是这样的:

++this.counter解释为this.counter = this.counter + 1。首先,计算等号右边的部分,因为实例没有counter属性,所以使用原型的计数器属性。这个属性的值将被添加到1,然后分配给this.counter,它现在创建一个本地属性,以同样的方式,当你分配一个根本不存在的属性时,比如a.xy = 1。在这种情况下,xy将是实例的本地属性。

编辑

有两种变通方法仍然可以让你使用prototype属性:

1)在count方法中显式地设置prototype属性:

ConstructorFunction.prototype.count = function() {
    return ++this.constructor.prototype.counter;
};

2)使用apply调用count方法,并使用原型作为上下文:

a.count.apply(a.constructor.prototype);

BUT,如果您按照您所做的方式设置prototype属性,那么这两个方法都会出现问题。

 ConstructorFunction.prototype = {
     //...
 };

这覆盖了整个原型对象,因此也覆盖了它的构造函数属性。构造函数属性现在将指向原型链中的下一个更高的对象,即Object对象。要解决这个问题,您可以在分配原型对象后手动设置构造函数:

ConstructorFunction.prototype.constructor = ConstructorFunction;

或者单独分配原型对象的每个属性:

ConstructorFunction.prototype.counter = 0;
ConstructorFunction.prototype.count = function () {
    return ++this.counter;
};

考虑使用闭包,这样你就可以将该变量保留为私有并在实例间共享:

var Class = (function ClassModule() {
  var counter = 0;
  function Class() {}
  Class.prototype = {
    count: function() {
      return counter++;
    }
  };
  return Class;
}());
var class1 = new Class();
var class2 = new Class();
console.log(class1.count()); //=> 0
console.log(class2.count()); //=> 1

counter变量保存在闭包的上下文中(模块模式),并且不会在每个新实例中重复。

在基于原型的OOD中,共享意味着共享相同的定义并将其用于不同的上下文中。如果你需要一个静态属性在上下文之间共享,你可以按照下面的方法做

var ConstructorFunction = function (context) {
    this.count = function () {
        return context + "," + (++this.counter) + "," + (++ConstructorFunction.staticCounter);
    };
};
ConstructorFunction.prototype.counter = 0;
ConstructorFunction.staticCounter = 0;
var context1 = new ConstructorFunction("context1");
var context2 = new ConstructorFunction("context2");
$("#output").append(context1.count());
$("#output").append(" ");
$("#output").append(context2.count());
http://jsfiddle.net/hdA6G/1/

和更好的定义方式

var ConstructorFunction = function (context) {
    this.context = context;
    this.counter = 0;
};
ConstructorFunction.staticCounter = 0;
ConstructorFunction.prototype.count = function () {
    return this.context + "," + (++this.counter) + "," + (++ConstructorFunction.staticCounter);
};
http://jsfiddle.net/hdA6G/3/

你把继承弄反了,原型从基对象继承。我认为这更接近于你想要完成的目标。

function MyObject () {
    this.count = 0;
};
ConstructorFunction.prototype = {
    counter: function () {
        return this.count++;
    },
    print: function () {
        return this.count;
    }
};

Var Foo = new MyObject();
console.log(Foo.counter()); // 1
console.log(Foo.counter()); // 2
console.log(Foo.print()); // 2

我希望这对你有帮助。

编辑

如果你想让你的计数器在所有实例中共享,那么它应该在你的基对象中。

function MyObject () {
    this.count = 0;
    this.counter = function () {
        return this.count++; //may not need the this
    }
};

我知道这是一个旧的帖子,但我是javascript的新手,在实验的时候我遇到了类似的东西,所以我想把我的2美分。

似乎每个对象在使用new实例化后都得到了自己在prototype中声明的变量的副本。从那时起,使用this访问将执行常规查找并找到要操作的私有副本。

然而,如果你在所有对象的创建之后创建一个原型变量,该变量将被共享并且表现得像静态的。我认为这很容易解释为什么会发生这种情况,但是,尽管如此,我发现这是一个有趣的黑客。我不确定这是否是技术规范中的一个可能在未来版本中解决的错误,或者是标准行为的副作用,所以不知道这是否可靠。我甚至不确定这是否是该语言的后续版本中新引入的"功能"。事实上,我开始在谷歌上搜索这个事实,看到了这篇文章。

试试这段代码。

var Worker = function (name) {
    this.name = name;
}
Worker.prototype.jobs = 0;
Worker.prototype.Work = function () {
    console.log("jobs finished", this.name, ++this.jobs);
}
Worker.prototype.WorkCount = function () {
    console.log("work count", this.name, this.workCount);
}
var ca = new Worker("ca");
var cb = new Worker("cb");
ca.Work();// shows 1
cb.Work();// shows 1
ca.WorkCount();// shows undefined
cb.WorkCount();// shows undefined
Worker.prototype.workCount = 2;
ca.WorkCount();// shows 2
cb.WorkCount();// shows 2