为什么在扩展对象时使用Object.create作为原型?

jer*_*ija 5 javascript inheritance prototype superclass

我有Java背景,最近我一直在尝试JavaScript继承.我开始写一些对象,在阅读了一些例子后,我发现了最适合我的代码风格.

这是我有的:

var Class = function() {};
Class.extend = function(p_constructor) {
    var Superclass = this;
    // the following line confuses me
    p_constructor.prototype = Object.create(Superclass.prototype);
    p_constructor.prototype.constructor = p_constructor;
    p_constructor.extend = Superclass.extend;
    return p_constructor;
};
Run Code Online (Sandbox Code Playgroud)

所以现在当我想定义一个扩展Class I的对象时,只需输入:

var Person = Class.extend(function(p_firstName, p_lastName) {
    this.firstName = p_firstName;
    this.lastName = p_lastName;
});
Run Code Online (Sandbox Code Playgroud)

以下是真实的:

var p = new Person('john', 'smith');
p instanceof Person; // true
p instanceof Class; // true
Run Code Online (Sandbox Code Playgroud)

我只是很难理解Class.extend函数中以下几行之间的有效区别:

/* 1) */ p_constructor.prototype = new Superclass();
/* 2) */ p_constructor.prototype = Superclass.prototype;
/* 3) */ p_constructor.prototype = Object.create(Superclass.prototype);
/* 4) */ p_constructor.prototype = Object.create(Superclass);
Run Code Online (Sandbox Code Playgroud)

我确实意识到如果一些超级构造函数抛出错误,使用第一行并不是很明智,但是第2,3和4行之间究竟有什么区别呢?

jer*_*ija 6

回答我自己的问题:

/* 1) */ p_constructor.prototype = new Superclass();
Run Code Online (Sandbox Code Playgroud)

就像我说的那样,使用它并不是很明智,因为它实际上创建了整个Superclass对象.原型继承的全部意义在于共享原型对象,因此可以避免冗余的功能(有时是对象)定义.

/* 2) */ p_constructor.prototype = Superclass.prototype;
Run Code Online (Sandbox Code Playgroud)

如果您可以确定构造函数的原型永远不会被第三方修改,那就没问题.假设使用您的类的人想要为其原型添加额外的功能.更改p_constructor的原型将直接影响超类的原型,并可能在超类的行为中引入错误.因此,使用下一行代码:

/* 3) */ p_constructor.prototype = Object.create(Superclass.prototype);
Run Code Online (Sandbox Code Playgroud)

这将创建一个新对象(实例),其原型(实际上是__proto__变量)设置为Superclass'原型.p_constructor.prototype现在的任何更改都不会对Superclass的行为进行任何更改.

/* 4) */ p_constructor.prototype = Object.create(Superclass);
Run Code Online (Sandbox Code Playgroud)

上面的行有效,但没有意义,因为它只将原型设置为Superclass的构造函数.

此外,以下行也让我感到困惑:

p_constructor.prototype.constructor = p_constructor;
Run Code Online (Sandbox Code Playgroud)

它对p_constructor的行为没有区别,它只对实例化对象中的构造函数进行引用.一个巧妙的技巧是将超类添加到原型中:

p_constructor.prototype.superclass = Superclass;
Run Code Online (Sandbox Code Playgroud)

然后下面的代码将起作用:

function Constructor(p_params) {
    // call constructor of the superclass
    this.superclass(p_params);
}
Run Code Online (Sandbox Code Playgroud)