>物业:物品 – 这将是一系列“过去”
>方法:Add() – 它将被抽象并由特定的“List”对象实现
>方法:Count() – 返回“items”的数量
然后创建将从“List”继承的子类
//Class 'List' function List(){ this.Items = new Array(); this.Add = function(){ alert('please implement in object') } } //Class CDList - which inherits from 'List' function CDList(){ this.Add = function(Artist){ this.Items.push(Artist) } } CDList.prototype = new List(); CDList.prototype.constructor = CDList; //Create a new CDList object var myDiscs = new CDList(); myDiscs.Add('Jackson'); myDiscs.Count() <-- this should be 1 //Create a second CDList object var myDiscs2 = new CDList(); myDiscs2.Add('Walt'); myDiscs2.Add('Disney'); myDiscs2.Count() <-- this should be 2
..但这似乎为所有’CDList’实例创建一个共享的’项目’列表.我需要以某种方式为每个“CDList”实例添加一个新的“Items”列表的继承实例.
我该怎么做?
*我在这个例子中使用’项目’列表作为例子.我希望能够在我的子类中为任何类型的继承属性新的实例 – 不一定是Array对象.
谢谢你们!
解决方法
要解决这个问题:不要将它附加到原型,而是附加到实例.这只能在施工时完成:
// This is the constructor of the parent class! function List() { this.Items = new Array(); } // Add methods to the prototype,not to the instance ("this") List.prototype.Add = function() { alert('please implement in object'); }; // Constructor of the child function CDList() { List.call(this); // <-- "super();" equivalent = call the parent constructor } // "extends" equivalent = Set up the prototype chain // Create a new,temporary function that has no other purpose than to create a // new object which can be used as the prototype for "CDList". You don't want to // call "new List();",because List is the constructor and should be called on // construction time only. Linking the prototypes directly does not work either,// since this would mean that overwriting a method in a child overwrites the // method in the parents prototype = in all child classes. var ctor = function() {}; ctor.prototype = List.prototype; CDList.prototype = new ctor(); CDList.prototype.constructor = CDList; // Overwrite actions CDList.prototype.Add = function(Artist) { this.Items.push(Artist); };
演示:http://jsfiddle.net/9xY2Y/1/
一般的概念是:每个实例必须具有自己的副本(在这种情况下就像“Items”数组))必须创建并附加到构造时的“this”(=实例),即在执行新的List( )或新的CDList().可以在实例之间共享的一切都可以附加到原型.这实际上意味着像“添加”功能这样的属性完全一次创建,然后被所有实例使用(导致原始问题).
连接原型时,您不得直接链接(通常),例如:
CDList.prototype = List.prototype; DVDList.prototype = List.prototype; // Now add a new function to "CDList" CDList.prototype.Foo = function() {alert('Hi'); };
因为“List”,“CDList”和“DVDList”三个函数的原型彼此直接链接,所以它们都指向一个原型对象,就是List.prototype.所以,如果你添加一些CDList.prototype,你实际上将它添加到List.prototype – 这也是“DVDList”的原型.
var dvd = new DVDList(); dvd.Foo(); // <-- alerts "hi" (oops,that wasn't intended...)
CDList.prototype = new List();
这将创建一个类型为“List()”的新对象,其特征是功能“List()”的原型链接到新对象,使您能够直接在对象上调用原型的属性:
var l = new List(); alert( l.hasOwnProperty("Add") ); // <-- yields "false" - the object l has no // property "Add" l.Add("foo"); // <-- works,because the prototype of "List" has a property "Add"
但是,请记住,我们打算使用函数“List()”的主体在每个实例的基础上创建像这个数组“Items”的东西?这是你放置任何“构造函数”代码的地方,例如
function User(userId) { $.getJSON('/user/' + userId,... } function Admin() {} Admin.prototype = new User( // ... now what?
var ctor = function() {}; // <-- does nothing,so its super safe // to do "new ctor();"
现在可以直接链接原型,因为我们永远不会添加任何东西到ctor.prototype:
ctor.prototype = List.prototype;
如果我们这样做:
CDList.prototype = new ctor();
“CDList()”的原型变成类型“ctor”的新对象,它没有自己的属性,但可以扩展.通过一个新的“添加”功能:
CDList.prototype.Add = function() { /* CD specific code! */ };
但是,如果您不向此新的原型对象添加“Add”属性,则“ctor()”的原型将会启动 – 这是“List()”的原型.这是所需的行为.
此外,“List()”中的代码现在只有当您执行新的List()或直接从另一个函数(通过List.call(this);的子类中)调用它)时才执行.