JavaScript: 构造函数 vs 原型

7

这个问题以前已经回答过了,但我想确认一下我的理解。在这段代码中:

var somePrototype = {
  speak: function() {
    console.log("I was made with a prototype");
  }
}

function someConstructor() {
  this.speak = function() {
    console.log("I was made with a constructor");
  }
}

var obj1 = Object.create(somePrototype);
var obj2 = new someConstructor();

obj1.speak();
obj2.speak();

它们本质上是在做同样的事情,对吗?唯一的区别是 function someConstructor() 是被提升的,这意味着如果需要,我可以在其定义之前调用它的新实例,而 var somePrototype 只能在其定义后调用。除此之外,没有其他区别了吗?


他们正在做类似的事情,但它们是非常明显不同的。 - Pointy
@dandavis 是的,之前已经解释过了 :) 然而,JavaScript和原型的语义很奇怪和令人困惑。 - Pointy
1
@SterlingArcher 当它被传入Object.create()时,它肯定是一个原型。 - Pointy
提升(Hoisting)在这里是最不相关的差异。如果你只是想知道这个,那么为什么还要把原型带入问题呢?你可以简化示例foo var foo = {bar: 42}; function baz() {}。你可以在定义之前调用baz,但不能调用foo - Felix Kling
1
@Pointy——啊,语言细微差别!如果一个对象被分配给函数的prototype属性,那么如果该函数从未被用作构造函数,它是否是原型呢?;-) - RobG
显示剩余3条评论
2个回答

8

使用Object.create()和构造函数调用这两种方法的区别在于:

创建对象:

  • Object.create(somePrototype)会创建一个新对象,并将somePrototype作为它的原型;
  • new someConstructor()使用构造函数调用创建一个对象。 obj2的原型是一个简单对象:new Object()

属性继承:

  • obj1继承了属性speak,它是一个函数。如果somePrototype对象中的此属性更改,则会影响继承它的任何使用Object.create(somePrototype)创建的对象。
    Object.keys(obj1)将返回[],因为该对象没有自己的属性。
  • obj2包含自己的属性speak。修改单个实例上的此属性不会影响使用new someConstructor()创建的任何其他实例。
    Object.keys(obj2)将返回['speak']作为其列出的属性。

构造函数:

  • obj1.constructor === Objecttrue
  • obj2.constructor === someConstructortrue

提升:

  • someConstructor被提升到其创建的作用域的顶部。因此,它可以在函数声明之前使用。
  • 当然,somePrototype不会与对象字面量一起被提升,因此应在设置值后使用。

请查看这篇有趣的文章,了解有关constructor属性的信息。


6
Object.create()调用创建一个对象并赋予您请求的原型。而new调用则创建一个由该构造函数直接装饰的对象。
区别在于,由构造函数创建的对象具有一个自有属性,其值为带有console.log()的函数。然而,Object.create()调用创建一个继承类似函数的原型对象的对象。
如果您将第一个对象传递给Object.keys(),则不会看到"speak"属性;如果您传递第二个对象,则会看到它。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接