JavaScript 继承:Object.create 与 new

IT技术 javascript inheritance object-create
2021-01-22 16:59:53

在 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
}
4个回答

在你的问题中,你提到过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对象不会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实际的作用。希望它会以某种方式有所帮助。

这个“MyClass.prototype = new SomeBaseClass()”是不是意味着在 MyClass 的实例还没有创建时创建了 SomeBaseClass 的新实例?
2021-03-18 16:59:53
我一直在寻找一种在 JS 中正确继承的超级简单方法,而无需使用任何库/框架。我认为这个例子(在我上面的小提琴中)是现代浏览器的最佳方法。也许 Object.Create polyfill 可以添加对旧浏览器的支持?
2021-03-27 16:59:53
有很多关于这个的话题,但没有像你这样的解释。+1
2021-04-01 16:59:53
嗨,谢赫。感谢您为此所做的努力。是的,不同之处在于构造函数在第二个示例中运行,而不是在第一个示例中运行。(这在我的情况下是可取的)。对于不是从super实现继承的未定义的公共属性,你只需要在子的构造函数中调用super:SomeBaseClass.call(this)。检查这个小提琴:jsfiddle.net/NhQGB
2021-04-03 16:59:53
所以基本上总结一下,如果您执行 .prototype = new 那么您将继承您在基类中分配给它的任何值,而当您执行 object.create 时,您仅继承了基类中原型上的内容,对吗?
2021-04-06 16:59:53

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

在你的情况下确实如此。

你什么时候会选择一个?

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

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

这是最好的答案,很好解释
2021-03-15 16:59:53

如果您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角默认的方式

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

我不是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(parent function) 原型并可以访问它的方法,但是如果您使用 new 创建子函数,它将返回一个全新的对象,其中包含我们不需要的所有父属性,并且在您创建任何父属性时使用“New”的对象或函数执行我们不想执行的父函数。

以下是要点

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