我很抱歉,因为这个话题出现了很多,但我今天读到的任何内容都没能充分解释这个问题。
我正在尝试创建一个简单的集合类(并同时学习javascript原型),用于存储具有“name”属性的对象,并允许其成员通过索引或值访问。到目前为止,我有这个:
function Collection() {}
Collection.prototype.constructor = Collection;
Collection.prototype._innerList = [];
Collection.prototype._xref = {};
Collection.prototype.count = function () { return this._innerList.length; };
Collection.prototype.add = function (obj) {
this._xref[obj.name] = this._innerList.push(obj) - 1;
}
Collection.prototype.get = function (id) {
if (typeof id == "string") {
return this._innerList[this._xref[id]];
} else {
return this._innerList[id];
}
};
问题:
var foo = new Collection();
foo.add({name: "someitem", value:"hello world"}); // foo.count()== 1
var bar= new Collection();
bar.add({name: "someotheritem", value:"hello world"}); // bar.count()== 2
嗯...
基本上,创建新实例bar
时,所有属性都具有foo
中数据的当前值。我知道我可以通过在构造函数中放置_xref等来解决这个问题,但我正在尝试理解原型如何工作。如果我创建一个新实例,并对该实例中的数据进行更改,那么当我创建另一个新实例时,为什么这些值会继续?
如果我从foo
或bar
的原型中对属性进行进一步更改,则它们是独立的,所以看起来我似乎并没有引用相同的任何实例。那么是什么导致bar
使用foo
的当前值进行实例化?
答案 0 :(得分:21)
考虑一个满是学生的教室。把东西放在原型上就像把东西放在白板上让所有人看到。当你宣布
时Collection.prototype._innerList = [];
你给每个收藏品都是属性的;无论是致电new Collection()
,白板的任何变化都会影响所有学生。但是,如果您在构造函数中定义它,或者将其中一个函数定义为this.variableName = []
,则每个副本都将拥有自己的variableName,就像向每个学生分发一份讲义一样。显然,在某些情况下,可以在白板上找到一些东西,例如从学生到学生的通用说明,但如果每个学生的每个项目都不同,那么它应该是个人财产。希望这种解释有意义......
你想这样做。
function Collection() {
if (!this instanceof Collection)
return new Collection();
this._innerList = [];
this._xref = {};
return this;
}
Collection.prototype.count = function() {
return this._innerList.length;
};
Collection.prototype.add = function(obj) {
this._xref[obj.name] = this._innerList.push(obj) - 1;
}
Collection.prototype.get = function(id) {
if (typeof id == "string") {
return this._innerList[this._xref[id]];
} else {
return this._innerList[id];
}
};
var foo = new Collection();
foo.add({name: "someitem", value:"hello world"});
console.log(foo.count()); // 1
var bar= new Collection();
bar.add({name: "someotheritem", value:"hello world"});
console.log(bar.count()); // 1
与你的问题不太相关,但这是我做的事情,所以我会把它扔出去。每当我在原型上做某事时,如果我没有回复某些东西,我会返回this
。它允许链接,因此只要instance.function1().function2().function3()
和function1
返回function2
,您就可以this
。
答案 1 :(得分:5)
您可以将原型视为为该类共享变量提供所有对象。就像c ++类中的静态变量一样,如果有意义的话。这对于函数来说是可以的,因为它们对于类的每个实例都是相同的。但是,如果您希望对象具有自己的非共享变量,则不应使用原型。一种简单的方法是在构造函数方法中分配它们,如下所示:
function Collection()
{
this._innerList = [];
this._xref = {};
}
Collection.prototype.count = function () { return this._innerList.length; };
Collection.prototype.add = function (obj) {
this._xref[obj.name] = this._innerList.push(obj) - 1;
}
Collection.prototype.get = function (id) {
if (typeof id == "string") {
return this._innerList[this._xref[id]];
} else {
return this._innerList[id];
}
};
var foo = new Collection();
foo.add({name: "someitem", value:"hello world"}); // foo.count()== 1
document.write(foo.count(),"<br>");
var bar= new Collection();
bar.add({name: "someotheritem", value:"hello world"}); // bar.cou
document.write(bar.count(),"<br>");