我试图按照this article中提出的想法和建议继承Array
。
这个Array
子类的一个重要目标,就是我在调用ArrayBase
时,它本身比Array
本身更容易进行子类化。我发现实现这一目标非常困难。 (但它可能看起来像我这样,因为我是一个JavaScript n00b!)
以下是ArrayBase
的实现,该实现基于前面引用文章towards the end提出的想法,并对我自己进行了一些改进。我还包括ArrayBase.slice
的实现,因为它说明了方案 1 的一个问题。
function ArrayBase () {
var arr = Array.prototype.constructor.apply(null, arguments);
var ctor = arr.constructor = arguments.callee;
arr.__proto__ = ctor.prototype;
return arr;
}
ArrayBase.prototype = new Array;
ArrayBase.prototype.slice = function () {
var ctor = this.constructor;
return ctor.apply(null,
Array.prototype.slice.apply(this, arguments));
}
var a0 = new ArrayBase(0, 1, 2, 3);
var a1 = a0.slice(2); // [2, 3]
console.log(a1 instanceof ArrayBase); // true
console.log(a1 instanceof Array); // true
到目前为止,这么好。当我现在尝试子类ArrayBase
时,问题就出现了。我发现执行此操作的唯一方法是基本上复制整个ArrayBase
构造函数(唯一的区别,非常轻微,发生在第一行)。随着继承,这是可怜的......
function MyArray () {
var arr = ArrayBase.apply(this, arguments);
var ctor = arr.constructor = arguments.callee;
arr.__proto__ = ctor.prototype;
return arr;
}
MyArray.prototype = new ArrayBase;
// behavior of MyArray
var a2 = new MyArray(1, 2, 3, 0);
var a3 = a2.slice(1); // [2, 3, 0]
console.log(a3 instanceof MyArray); // true
console.log(a3 instanceof ArrayBase); // true
console.log(a3 instanceof Array); // true
console.log(a3.join(':')); // "2:3:0"
a3[5] = 1;
console.log(a3.length); // 6
a3.length = 2;
console.log(a3.toString()) // "2,3"
我的问题:
如何消除
ArrayBase
和MyArray
构造函数之间存在的重复,同时仍然保留// behavior of MyArr
行之后的行所示的行为?该方案是否也可以在子类化MyArray
时使用?
(我意识到反对建造高大的遗产塔的论点,但不管它们是否设计良好,我希望它们至少得到合理的实施。)
1 如果Array
的继承符合我认为的那样,则没有必要实施ArrayBase.slice
,但不幸的是slice
ArrayBase
从Array
继承的方法没有显示返回与this
相同类的对象的基本OOP。
答案 0 :(得分:2)
在回答你的问题之前,对代码有一些评论: - )
var arr = Array.prototype.constructor.apply(null, arguments);
自Array.prototype.constructor === Array
起,请勿复制此内容。
var ctor = arr.constructor = …
没有理由在这里创建一个属性。如果任何事物都需要constructor
属性,那么它应该从该构造函数的.prototype
对象继承。
arguments.callee;
请勿使用已弃用的arguments.callee
!你知道它指向ArrayBase
。
arr.__proto__ = ctor.prototype;
您可能知道__proto__
是非标准的(并且在IE中尤其不起作用),但我们在这里需要原型注入技术。不过,不要忘记这个事实!
ArrayBase.prototype = new Array;
做not use new
for setting up inheritance!您不想在此处调用初始化程序(即“构造函数”)。请改用Object.create
。
现在,回到你的问题:
如何消除我的
ArrayBase
和MyArray
构造函数之间存在的重复?
实际上你已经使用过这个概念了。您的ArrayBase.prototype.slice
实现适用于每个子类 - 再次构造this.constructor
的实例。您可以对ArrayBase
构造函数使用相同的方法:
function ArrayBase() {
var arr = Array.apply(null, arguments);
var ctor = this.constructor;
arr.__proto__ = ctor.prototype;
return arr;
}
/* irrelevant for the answer, but helpful:
ArrayBase.prototype = Object.create(Array.prototype, {
constructor: {value: ArrayBase}
});
Object.keys(Array.prototype).forEach(function(k) {
if (typeof Array.prototype[k] != "function") return;
ArrayBase.prototype[k] = function() {
var arr = Array.prototype[k].apply(this, arguments);
if (Array.isArray(arr))
arr.__proto__ = Object.getPrototypeOf(this);
return arr;
};
});
*/
function MyArray() {
return ArrayBase.apply(this, arguments);
}
MyArray.prototype = Object.create(ArrayBase.prototype, {
constructor: {value: MyArray}
});