JavaScript 继承: Object.create vs new

在 JavaScript 中,这两个例子的区别是什么:

先决条件:

function SomeBaseClass(){
}


SomeBaseClass.prototype = {
doThis : function(){
},


doThat : function(){
}
}

继承示例使用 Object.create:

function MyClass(){
}


MyClass.prototype = Object.create(SomeBaseClass.prototype);

使用 new 关键字的继承示例 B

function MyClass(){
}


MyClass.prototype = new SomeBaseClass();

这两个例子似乎做同样的事情。什么时候你会选择其中一个而不是另一个?

还有一个问题: 考虑下面的链接(第15行)中的代码,其中对函数自己的构造函数的引用存储在原型中。这有什么用?

https://github.com/mrdoob/three.js/blob/master/src/loaders/ImageLoader.js

摘录(如果你不想打开链接) :

THREE.ImageLoader.prototype = {


constructor: THREE.ImageLoader
}
44387 次浏览

如果按照设想使用 Object.create(),差异就会变得很明显。实际上,它完全从你的代码中隐藏了 prototype单词,它会在引擎盖下完成工作。使用 Object.create(),我们可以像

var base =  {
doThis : function(){
},


doThat : function(){
}
};

然后我们可以从这里继承/扩展其他对象

var myObject = Object.create( base );
// myObject will now link to "base" via the prototype chain internally

所以这是另一个概念,一种更“面向对象”的继承方式。例如,没有使用 Object.create()的“构造函数”。当然,您可以在这些对象中创建并调用一个自定义的 构造函数构造函数

使用 Object.create()的一个原因是,与使用 Javascript 默认方式相比,它可能看起来更像从其他对象继承的 自然混音/* 。

这两个例子似乎做同样的事情。

对你来说是这样。

你什么时候会选择其中一个?

SomeBaseClass有一个函数体时,这将使用 new关键字执行。这通常是不打算-您只想设置原型链。在某些情况下,它甚至可能导致严重的问题,因为实际上 实例化是一个对象,其私有作用域变量由所有 MyClass实例共享,因为它们继承相同的特权方法。其他副作用是可以想象的。

So, you should generally prefer Object.create. Yet, it is not supported in some legacy browsers; which is the reason you see the new-approach much too frequent as it often does no (obvious) harm. Also have a look at 这个答案.

在你的问题中,你提到了 Both examples seem to do the same thing,这根本不是真的,因为

你的第一个例子

function SomeBaseClass(){...}
SomeBaseClass.prototype = {
doThis : function(){...},
doThat : function(){...}
}
function MyClass(){...}
MyClass.prototype = Object.create(SomeBaseClass.prototype);

In this example, you are just inheriting SomeBaseClass' prototype but what if you have a property in your SomeBaseClass like

function SomeBaseClass(){
this.publicProperty='SomeValue';
}

如果你把它当做

var obj=new MyClass();
console.log(obj.publicProperty); // undefined
​console.log(obj);​

obj对象不会像 在这个例子中那样具有 publicProperty属性。

你的第二个例子

MyClass.prototype = new SomeBaseClass();

它执行 constructor函数,创建一个 SomeBaseClass的实例并继承整个 SomeBaseClass对象

    var obj=new MyClass();
console.log(obj.publicProperty); // SomeValue
console.log(obj);​

在这种情况下,它的 publicProperty属性对于 obj对象(如 在这个例子中)也是可用的。

由于 Object.create在一些旧的浏览器中不可用,在这种情况下,您可以使用

if(!Object.create)
{
Object.create=function(o){
function F(){}
F.prototype=o;
return new F();
}
}

上面的代码只是添加了 Object.create函数,如果它不可用,所以你可以使用 Object.create函数,我认为上面的代码描述了什么 Object.create实际上做。希望能有所帮助。

我不是 Java 脚本的专家,但是这里有一个简单的例子来理解“ Object.create”和“ new”之间的区别。.

步骤1: 使用一些属性和操作创建父函数。

function Person() {


this.name = 'venkat';


this.address = 'dallas';


this.mobile='xxxxxxxxxx'


}


Person.prototype.func1 = function () {


return this.name + this.address;
}

步骤2: 创建一个子函数(PersonSalary) ,该函数使用 新的关键字扩展 Person 函数。

function PersonSalary() {
Person.call(this);
}
PersonSalary.prototype = new Person();


PersonSalary();

步骤3: 创建第二个子函数(PersonLeaf) ,它使用 Object.create关键字扩展了 Person 函数。

function PersonLeaves() {
Person.call(this);
}
PersonLeaves.prototype = Object.create(Person.prototype);




PersonLeaves();

//现在检查两个子函数原型。

PersonSalary.prototype
PersonLeaves.prototype

这两个子函数都会链接到 Person (父函数)原型,并且可以访问它的方法,但是如果你使用 New 创建子函数,它会返回一个全新的对象,其中包含我们不需要的所有父属性,而且当你使用“ New”创建任何对象或函数时,父函数会被执行,而我们不希望这样。

这是外卖

如果您只想委托给父函数中的某些方法,并且不希望创建新对象,那么使用 Object.create 是最好的方法。

在这个答案集中增加了一些内容,注意到 JS 现在显然已经有了本机类:

  1. 在示例 A 和示例 B 中都没有配置静态继承链。
  2. 在例 B 中,超类构造函数在“错误的时间”运行。它在调用之前运行以实例化子类的实例,在知道任何参数之前,也许在您决定实例化子类的实例之前。请注意,构造函数可以包含任何它们喜欢的逻辑,包括副作用逻辑,因此这可能是有影响的。

ES6之后,继承链可以使用 classextends关键字(解决了这两个问题)以标准化的方式进行配置。

参见 还有