Javascript原型和实例创建

时间:2011-04-29 21:54:53

标签: javascript prototype

我很抱歉,因为这个话题出现了很多,但我今天读到的任何内容都没能充分解释这个问题。

我正在尝试创建一个简单的集合类(并同时学习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];
    }
};

http://jsfiddle.net/YrVFZ/

问题:

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等来解决这个问题,但我正在尝试理解原型如何工作。如果我创建一个新实例,并对该实例中的数据进行更改,那么当我创建另一个新实例时,为什么这些值会继续?

如果我从foobar的原型中对属性进行进一步更改,则它们是独立的,所以看起来我似乎并没有引用相同的任何实例。那么是什么导致bar使用foo的当前值进行实例化?

2 个答案:

答案 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

http://jsfiddle.net/vXbLL/

修改

与你的问题不太相关,但这是我做的事情,所以我会把它扔出去。每当我在原型上做某事时,如果我没有回复某些东西,我会返回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>");