JavaScript继承:Object.create vs new

时间:2012-10-23 23:07:37

标签: javascript inheritance object-create

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

先决条件:

function SomeBaseClass(){
}

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

    doThat : function(){
    }
}

继承示例A使用Object.create:

function MyClass(){
}

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

继承示例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 个答案:

答案 0 :(得分:110)

在你提出的问题中,你提到了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实际上做了什么。希望它能以某种方式提供帮助。

答案 1 :(得分:39)

  

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

在你的情况下这是真的。

  

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

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

因此,您通常应该更喜欢Object.create。然而,某些传统浏览器不支持它;这就是你看到new - 方法过于频繁的原因,因为它往往没有(明显的)伤害。另请查看this answer

答案 2 :(得分:8)

如果按预期使用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()的一个论点是,与其他对象相比,它可能看起来更自然 mix / * inherit *,而不是使用Javascripts 默认值方式

答案 3 :(得分:0)

我不是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:创建第二个子函数(PersonLeaves),使用 Object.create 关键字扩展到Person函数之上。

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


PersonLeaves();

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

PersonSalary.prototype
PersonLeaves.prototype

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

以下是要点

  

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