使用以这种形式编写的代码(您没有使用new
并且您拥有真正的私有数据),主要的绊脚石是Character
没有可以在实例之间共享的任何内容。因此,虽然您可以将生成的对象Character
用作其他对象的原型,但您不能拥有一个 Character
对象并将其重用为多个派生对象的原型。
以下是如何编写一个函数(Villian
例如)生成对象,每个对象都将自己的底层Character
对象作为原型:
function Villian(startX) {
var rv = Object.create(Character(startX));
rv.doEvilThing = function() {
};
return rv;
}
Villian
创建一个新Character
对象并将其分配为对象Villian
创建的原型。当然,这意味着每次调用Villian
都会创建两个对象,而不是像Character
我们可以在 s 之间重用的部分那样只创建一个对象Villian
。
您可以直接Villian
从以下位置扩展对象Character
:
function Villian(startX) {
var rv = Character(startX);
rv.doEvilThing = function() {
};
return rv;
}
那只创建一个对象,并没有区分它Villian
的方面和Character
方面。
如果Character
这样写是因为您想要x
并且swipe
真正私有(尽管两者都有 setter 和 getter,我没有看到太多理由),您可能希望使用将成为基础的模式ES6 的私有属性,与您当前使用的模式不同,它对共享原型对象很友好。
我已经写了一篇文章,介绍如何在不等待新的 ES6 特性的情况下今天几乎可以做到这一点。简而言之:ES6 将引入新的 " Name
" 对象,它们不是字符串,但可以用作属性的名称。引用属性时,可以使用该对象而不是名称。例如:
var x = new Name(); // Create the private name object
this[x] = value; // Put a property on the object with that name
私有Name
对象是不透明的,默认情况下用它们创建的属性是不可枚举的。
这是整体模式。(我在这里尝试坚持您的编码风格,对变化表示歉意。)请注意,这些Character
并Villian
要求您new
与它们一起使用,与您的Character
上述不同。下面我将展示如何做到这一点new
(这是一个小改动)。
var Character = (function() {
var x = new Name(); // The *name* for our `x` property
var swipe = new Name(); // The *name* for our `swipe` property
/* Character class*/
var Character = function(startX) {
this[x] = startX;
this[swipe] = 0;
};
Character.prototype.getX = function() {
return this[x];
};
Character.prototype.getSwipe = function(){
return this[swipe];
};
// ...etc...
return Character;
})();
var Villian = (function() {
/* Villian class*/
var Villian = function(startX) {
Character.call(this, startX);
};
Villian.prototype = Object.create(Character.prototype);
Villian.prototype.doEvilThing = function() {
// ...
};
return Villian;
})();
请注意,我们现在在原型上有各种方法,并且属性确实是属性(而您使用的模式是私有的,但不是属性),但是由于我们的作用域函数之外的任何代码都无法访问Name
对象他们,没有外部代码可以使用这些属性。
在 ES5 和更早版本(例如,今天)上,您需要一个函数来代替 ES6 的Name
. 我在文章中给出的只是使用不重复的随机字符串:
var Name = function() {
var used = {};
function Name() {
var length, str;
do {
length = 5 + Math.floor(Math.random() * 10);
str = "_";
while (length--) {
str += String.fromCharCode(32 + Math.floor(95 * Math.random()));
}
}
while (used[str]);
used[str] = true;
return new String(str); // Since this is called via `new`, we have to return an object to override the default
}
return Name;
}();
你可以在没有new
. 唯一改变的是实际Character
和Villian
功能,但为了清楚起见,我将包括整个事情:
var Character = (function() {
var x = new Name(); // The *name* for our `x` property
var swipe = new Name(); // The *name* for our `swipe` property
/* Character class without using `new` */
var Character = function(startX) {
var c = Object.create(Character.prototype);
c[x] = startX;
c[swipe] = 0;
return c;
};
Character.prototype.getX = function() {
return this[x];
};
Character.prototype.getSwipe = function(){
return this[swipe];
};
// ...etc...
return Character;
})();
var Villian = (function() {
/* Villian class without using `new` */
var Villian = function(startX) {
var v = Object.create(Villian.prototype);
Character.call(v, startX);
return v;
};
Villian.prototype = Object.create(Character.prototype);
Villian.prototype.doEvilThing = function() {
// ...
};
return Villian;
})();