utils.inherits 中存在着预先存在的子类原型属性和构造函数的意外行为的可能性
我一直在研究 utils.inherits 辅助函数以及它如何设置原型链。我遇到了一些可能值得讨论的行为,特别是与子类原型上已存在的属性以及 constructor 属性本身的交互。在 lib/utils.js 中, inherits 的当前实现似乎是:
exports.inherits = function (ctor, superCtor) {
var Obj = function() {};
Obj.prototype = superCtor.prototype;
ctor.prototype = new Obj();
};
这个方法有效地建立了原型链。然而,行 ctor.prototype = new Obj(); 完全替换了 ctor.prototype 对象。
这可能有以下几个潜在影响:
1. 丢失子类原型属性:如果在调用 inherits(ctor, superCtor) 之前在 ctor.prototype 上添加了方法或属性,它们似乎会丢失,因为原始原型对象被丢弃。例如,在以下场景中:function Parent() {} function Child() {} Child.prototype.myMethod = function() { /* ... */ }; // 在调用 inherits 之前定义 utils.inherits(Child, Parent); // const c = new Child(); // c.myMethod(); // 这可能会返回 undefined inherits.test.cjs 中的测试用例 it('should work with constructors that have prototype methods') 似乎突出了这一点,因为 child.childMethod 意外地为 undefined。 2. 子类原型上的 constructor 属性:在 ctor.prototype 被替换之后,新的 ctor.prototype.constructor 属性自然会指向 Obj(内部使用的临时构造函数)。虽然标准的继承模式通常包括重置 ctor.prototype.constructor = ctor;以建立原型链,但当前的 utils.inherits 似乎不包括此步骤。inherits.test.cjs 中的测试用例 it('should properly set up prototype inheritance between constructors') 和 it('should properly maintain the constructor property') 断言 Child.prototype.constructor 为 Child。考虑到 inherits 的实现,这些断言可能不成立,因为 Child.prototype.constructor 可能为 Obj。 这种行为可能是出于特定内部用例的设计,或者可能是 JSZip 中的惯例,总是在调用 utils.inherits 之后将方法添加到子类的原型中。 然而,如果 inherits 函数是用于更广泛的用例,或者旨在与 JavaScript 的常见继承模式(如过去 Node.js 的 util.inherits 或 Object.create)保持一致,那么这些方面可能会导致开发人员或库本身出现意外结果,如果不加以谨慎管理。 也许这是一个函数行为可以在注释中进行澄清的领域,或者如果希望实现更广泛的兼容性,则可以重新审视其实现,以保留现有的子类原型成员并明确设置 constructor 属性。
内容来源: Stuk/jszip