Javascript 原型和实例创建
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5837795/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Javascript prototypes and instance creation
提问by Jamie Treworgy
I apologize because this topic comes up a lot, but I have not been able to have this adequately explained in anything I've read today.
我很抱歉,因为这个话题经常出现,但我今天读到的任何东西都没有充分解释这一点。
I am trying to make a simple collection class (and learn about javascript prototyping at the same time) designed to store objects with a "name" property and lets its members be accessed by index or value. So far I've got this:
我正在尝试创建一个简单的集合类(并同时了解 javascript 原型设计),旨在存储具有“名称”属性的对象,并允许通过索引或值访问其成员。到目前为止,我有这个:
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];
}
};
The problem:
问题:
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
Hmm...
唔...
Basically, the new instance bar
is created with all the properties having the current values of the data in foo
. I know I can fix this by putting _xref, etc. inside the constructor, but I'm trying to understand how prototyping works. If I create a new instance, and make changes to the data in that instance, why would those values carry over when I create another new instance?
基本上,新实例bar
是使用所有具有当前数据值的属性创建的foo
。我知道我可以通过将 _xref 等放在构造函数中来解决这个问题,但我试图了解原型设计的工作原理。如果我创建一个新实例,并对该实例中的数据进行更改,为什么在我创建另一个新实例时这些值会继续存在?
If I make further changes to a property from the prototype of foo
or bar
they are independent, so it doesn't seem as if I'm somehow referencing the same instance of anything. So what is causing bar
to be instantiated with the current values from foo
?
如果我对原型中的属性进行进一步更改,foo
或者bar
它们是独立的,那么似乎我不会以某种方式引用任何事物的相同实例。那么是什么导致bar
使用当前值进行实例化foo
?
回答by Robert
Consider a classroom full of students. Putting something on the prototype is like putting something on the white board for them all to see. When you're declaring
考虑一个满是学生的教室。把东西放在原型上就像把东西放在白板上给他们所有人看。当你宣布
Collection.prototype._innerList = [];
you're giving every collection that property; regardless of calling new Collection()
any changes to the white board affects all students. However, if you define it within the constructor, or one of the functions as this.variableName = []
, each copy will have its own variableName, like handing each student a handout. Obviously, there's some cases when it's okay to have something on the white board, such as instructions that will be universal from student to student, but if each item is going to be different for each student, it should be an individual property. Hope this explanation makes sense...
你给每一个收藏品那个财产;无论调用new Collection()
白板的任何更改都会影响所有学生。但是,如果您在构造函数或其中一个函数this.variableName = []
中将其定义为 as ,则每个副本都将具有自己的 variableName,就像向每个学生分发讲义一样。显然,在某些情况下,白板上有一些东西是可以的,例如对学生通用的说明,但如果每个项目对每个学生都不同,它应该是一个单独的属性。希望这个解释有意义...
You want to be doing this.
你想这样做。
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
Edit
编辑
Not really relevant to your question, but it's something I do so I will throw it out there. Whenever I'm doing something on the prototype, if I'm not returning something, I return this
. It allows chaining, so you could do instance.function1().function2().function3()
as long as function1
and function2
return this
.
与你的问题并不真正相关,但这是我所做的,所以我会把它扔在那里。每当我在原型上做一些事情时,如果我没有返回一些东西,我就会返回this
. 它允许链接,所以你可以做instance.function1().function2().function3()
只要function1
并function2
返回this
。
回答by Brian Rothstein
You can think of a prototype as giving all objects of that class shared variables. Like static variables in a c++ class if that makes any sense. That's ok to do for functions because they're all the same for each instance of the class. However, if you want the object to have its own non-shared variable, you shouldn't use the prototype. One simple way to do it is to assign them in the constructor method like this:
您可以将原型视为为该类的所有对象提供共享变量。如果有任何意义,就像 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>");