JavaScript 继承:Object.create 与 new

Posted

技术标签:

【中文标题】JavaScript 继承:Object.create 与 new【英文标题】:JavaScript inheritance: Object.create vs new 【发布时间】:2012-10-13 23:44:56 【问题描述】:

javascript 中这两个例子有什么区别:

先决条件:

function SomeBaseClass()


SomeBaseClass.prototype = 
    doThis : function()
    ,

    doThat : function()
    

使用 Object.create 的继承示例 A:

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

【问题讨论】:

为什么这会被标记为重复!?!另一个问题和答案甚至都没有提到Object.create。这是一个错误,应该重新打开。 如果有的话,它是***.com/questions/4166616/…的副本 对该评论投了 13 票但仍未重新打开..?! 【参考方案1】:

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

你的第一个例子

function SomeBaseClass()...
SomeBaseClass.prototype = 
    doThis : function()...,
    doThat : function()...

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

在本例中,您只是继承了SomeBaseClass' prototype,但如果您的SomeBaseClass 中有一个属性,例如

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

如果你像这样使用它

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

obj 对象不会像in this example 那样具有publicProperty 属性。

你的第二个例子

MyClass.prototype = new SomeBaseClass();

它正在执行constructor 函数,创建SomeBaseClass 的实例并继承整个SomeBaseClass 对象。所以,如果你使用

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

在这种情况下,它的publicProperty 属性也可用于obj 对象,如in this example。

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

if(!Object.create)

    Object.create=function(o)
        function F()
        F.prototype=o;
        return new F();
    

上面的代码只是添加了Object.create 函数,如果它不可用,那么你可以使用Object.create 函数,我认为上面的代码描述了Object.create 的实际作用。希望它会在某种程度上有所帮助。

【讨论】:

嗨,谢赫。感谢您为此付出的努力。是的,不同之处在于构造函数在第二个示例中运行,而不是在第一个示例中运行。 (在我的情况下这是可取的)。对于不是继承自super实现的undefined public property,只需要在child的构造函数中调用super:SomeBaseClass.call(this)即可。检查这个小提琴:jsfiddle.net/NhQGB 我一直在寻找一种超级简单的方式在 JS 中正确继承而不使用任何库/框架。我认为这个例子(在我上面的小提琴中)是现代浏览器的最佳方法。也许 Object.Create polyfill 可以增加对旧版浏览器的支持? 所以基本上总结一下,如果你做 .prototype = new 那么你继承了你在基类中分配给它的任何值,当你做 object.create 时,你只是继承了基类中的原型,对吧? 这个“MyClass.prototype = new SomeBaseClass()”是否意味着在MyClass的实例还没有创建的时候创建了SomeBaseClass的新实例? 关于这个的话题很多,但没有像你这样的解释。 +1【参考方案2】:

我不是 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),它使用 New 关键字扩展上述 Person 函数..

function PersonSalary() 
    Person.call(this);

PersonSalary.prototype = new Person();

PersonSalary();

第 3 步:创建第二个子函数 (PersonLeaves),它使用 Object.create 关键字在 Person 函数之上扩展..

function PersonLeaves() 
 Person.call(this);

PersonLeaves.prototype = Object.create(Person.prototype);


PersonLeaves();

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

PersonSalary.prototype
PersonLeaves.prototype

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

这里是要点

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

【讨论】:

【参考方案3】:

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

你的情况确实如此。

你什么时候会选择一个而不是另一个?

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

因此,您通常应该更喜欢Object.create。但是,某些旧版浏览器不支持它;这就是你看到new-方法过于频繁的原因,因为它通常没有(明显的)伤害。也可以看看this answer。

【讨论】:

这是最好的答案,很好解释【参考方案4】:

如果您按预期使用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() 的一个理由是,它可能看起来更自然 混合/*继承*来自其他对象,而不是使用 Javascripts 默认方式。

【讨论】:

Object.create 在需要构造函数时不能真正用new 代替经典方法 绝对可以@Bergi。看看这篇博文:davidwalsh.name/javascript-objects-deconstruction。您还可以将初始化对象作为第二个参数传递给 Object.create()。 @LocalPCGuy:不,它不能,因为Object.create 不会调用创建闭包所必需的函数。当然,使用Object.create,您可以在对象上放置一个init 方法并立即调用它,它甚至可能返回this,以便您获得简洁的语法 - 但是等等,然后构造函数。 调用初始化函数的工作方式类似于构造函数,但它不是构造函数。而且该方法确实允许您用 Object.create 完全替换经典方法。并且对象链接的心理模型比通过“new”创建的要简单得多。 嗯,我的new 心智模型使用“对象链接”,所以没有太大区别。事实上,只有两件事:.constructor 被称为.init,并且该函数没有指向原型对象的.prototype 属性。其余的只是语法 - 我更喜欢 new X 而不是 Object.create(x).init()

以上是关于JavaScript 继承:Object.create 与 new的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript常见继承方式

JavaScript之继承(原型链)

javascript之继承

JavaScript之继承(原型链)

[ JavaScript ] JavaScript 实现继承.

JavaScript之继承