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的主要内容,如果未能解决你的问题,请参考以下文章