使用'Object.create()'而不是'new'关键字来理解原型对象的创建

Kar*_*lek 10 javascript constructor prototype object

我来到一个包含这些行的代码

var data = function() {
    function Metadata() { /*some initialization here*/ }

    Metadata.prototype = Object.create(Backend.prototype);
    Metadata.prototype.constructor = Metadata;

    return Metadata;
}
Run Code Online (Sandbox Code Playgroud)

我很难理解实际发生了什么,以及如何使用返回的对象.如果我理解正确,data现在将是一个应该像这样初始化的对象

var d = new data()
Run Code Online (Sandbox Code Playgroud)

但我不明白以下几行,为什么Object.create()用而不是new关键字:

Metadata.prototype = Object.create(Backend.prototype);
Metadata.prototype.constructor = Metadata;
Run Code Online (Sandbox Code Playgroud)

他们在做什么?他们有必要吗?和之间有什么区别Object.createnew

wjo*_*sto 5

这两条线是Metadata扩展的典型方式Backend.

JavaScript中的类被定义为函数.如果定义prototypeon函数,则可以使用new关键字(或Object.create)来创建类的实例.原型上的函数/属性将位于您创建的类的新实例上.

在上面的代码中,Metadata.prototype正被设置为一个实例Backend,因此Metadata.prototype将继承调用方法/属性Backend.prototype.

您可以在继承和原型链中找到更多信息.

  • 当你使用`Object.create`时,不会调用构造函数.因此,如果您只想扩展`Backend`的原型,那么`Object.create`是有道理的. (2认同)

Lud*_*ltz 5

JavaScript是一种基于原型的语言. 这意味着它不像其他语言那样使用class关键字.相反,JavaScript使用函数作为类.
在您的示例中,数据变量可以被同化为一个:

var Data = function() { ... }

要创建此类的实例,我们使用new关键字将类型object的结果分配给变量.

var data = new Data()

从ECMA Script 6开始,我们可以使用实例化方法Object.create(),该方法使用指定的原型对象和属性创建一个未启动的对象.它接受参数,该对象应该是新创建的对象的原型.(它还复制构造函数)

因此,以下行是一种使元数据扩展Backend对象并保留其自己的构造函数的方法:

// Metadata extends Backend
Metadata.prototype = Object.create(Backend.prototype);
Metadata.prototype.constructor = Metadata;
Run Code Online (Sandbox Code Playgroud)

但是这段代码并不完全等同于 Metadata.prototype = new Backend();.看这个例子:

//Base class
var Backend = function(){ this.publicProperty='SomeValue'; }

//Extension class 1
var Metadata1 = function() { }
Metadata1.prototype = Object.create(Backend.prototype);
Metadata1.prototype.constructor = Metadata1;

//Extension class 2
var Metadata2 = function() { }
Metadata2.prototype = new Backend();


/*
 *  Then the results are different (see code snippet at the end of this post)
 */
//result1 = 'undefined'
var data1 = new Metadata1();
var result1 = data1.publicProperty;

//result2 = 'SomeValue'
var data2 = new Metadata2();
var result2 = data2.publicProperty;
Run Code Online (Sandbox Code Playgroud)

实际上两者都非常相似,主要区别在于new关键字实际上运行构造函数代码,而Object.create不会执行代码.

另一个区别是Object.create你可以创建一个不从任何东西继承的对象(Object.create(null)).
而如果你这样做Metadata.prototype = null,新创建的对象将继承自Object.prototype


注意:在某些旧版浏览器(IE8及以下版本)中,您可以使用此等效代码Object.create:

Object.create = function(o){
    function F(){}
    F.prototype=o;
    return new F();
}
Run Code Online (Sandbox Code Playgroud)

以下是显示两种方法之间差异的工作代码段

//Base class
var Backend = function(){ this.publicProperty='SomeValue'; }

//Extension class 1
var Metadata1 = function() { }
Metadata1.prototype = Object.create(Backend.prototype);
Metadata1.prototype.constructor = Metadata1;

//Extension class 2
var Metadata2 = function() { }
Metadata2.prototype = new Backend();


//result: 'undefined'
var data1 = new Metadata1();
$("#result1").text("result1: " +  (typeof data1.publicProperty=='undefined' ? 'undefined' : data1.publicProperty));

//result: 'SomeValue'
var data2 = new Metadata2();
$("#result2").text("result2: " +  (typeof data2.publicProperty=='undefined' ? 'undefined' : data2.publicProperty));
Run Code Online (Sandbox Code Playgroud)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="result1"></div>
<div id="result2"></div>
Run Code Online (Sandbox Code Playgroud)