为什么在创建原型时不鼓励使用构造函数?


10

快速背景:在JavaScript中,每种对象类型的构造函数都有一个prototype属性。的prototype是指一个对象,各构造对象的用途如在其原型链中的下一步骤的。当您希望一种类型可以是另一种类型固有的类型时,可以将prototype子类型的设置为父类型的新实例。

例如:

var Parent = function() { /* constructor business */ }
Parent.prototype.parentProp = "some parent property";

var Child = function() { /* constructor business */ }
Child.prototype = /*** !! Some prototype object goes here !! ***/

我的问题询问上面的代码中应在“ Some prototype object goes here”位置添加哪些代码。我的第一个本能是构造父对象的实例(即new Parent()),但在评论“关于将这样的对象原型复制到另一个对象的安全方法吗?”的评论中。,一位用户写道:

不,请勿new bar()用于原型对象!

(...这是我在许多答案和评论中都看到的一种观点,但这是我目前手头唯一的例子。)

另一种选择是Object.create(Parent.prototype)用作Child.prototype。据我所知,这还会创建一个新Parent实例,但不会运行Parent构造函数。

有人可以解释为什么从父类型生成原型对象时应避免运行构造函数的原因吗?是否会出现一些重大的技术问题(也许具有多个继承级别)?还是这种模式会误用构造函数,从而与一些典型的最佳实践相冲突(例如,在创建原型时运行构造函数违反了某些关注点分离)?

Answers:


5

因为它是一个不需要调用的函数。new与JavaScript中的常规函数​​调用没有什么不同。

构造函数可以做的不仅仅是设置字段。例如,如果它验证传入的数据,那么当您仅尝试设置继承链时,将导致验证错误。

而且您不需要Object.create,这就足够了:

function objectCreate( proto ) {
    function T(){}
    T.prototype = proto;
    return new T();
}

但这正是Object.create实现的方式。
Casey Chu

@CaseyChu一点也不。我提到它是因为在链接的帖子中有人说“ Object.create在IE8中不起作用”-当您可以在2秒内在任何浏览器上针对此用例实现它时,这只是无用的注释。
Esailija

2

现在,我的理解范围有所扩大,我想以一个具体的例子为基础建立Esailija的答案

一个特殊的问题是构造函数可以设置实例特定的属性。因此,如果您使用通过创建的原型对象new,则所有子实例都可以共享该原型中单个构造函数定义的实例特定属性。

例如,假设Parent每个实例都有一个唯一的id属性设置为构造时间:

var Parent = function() { this.id = Math.random(); }
Parent.prototype.parentProp = "some parent property";

var Child = function() { /* constructor business */ }
Child.prototype = new Parent();

这将导致所有 Child实例共享一个id继承自new Parent()作为唯一对象的唯一原型属性Child.prototype

对于这种情况,更好的方法是Object.create在子构造函数内部使用并直接调用父构造函数(如果需要):

var Parent = function() { this.id = Math.random(); }
Parent.prototype.parentProp = "some parent property";

var Child = function() {
    // run `this` through the Parent constructor function
    Parent.apply(this, arguments);
}
Child.prototype = Object.create(Parent.prototype);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.