19

如果我错了,请告诉我:

原型是一个普通的对象。当一个对象继承一个原型时,它不只是复制原型的属性,对象存储了对原型的引用。

在 Firefox 中,我可以这样做:

var food = {fruit:"apple"};
var more_food = {vegetable:"celery"};
food.__proto__ = more_food;
food.vegetable // celery
food.fruit // apple

我可以使用该__proto__属性手动设置对原型对象的引用。

我也可以使用Object.create

var food = {fruit:"apple"};
var more_food = {vegetable:"celery"};
food = Object.create(more_food);
food.vegetable // celery
food.fruit // undefined

究竟在Object.create做什么?变量 food 是分配了对原型 more_food 的引用,还是 Object.create 只是返回了对象 more_food 的副本?如果Object.create只是复制,那么如果变量 food 没有引用 more_food,原型链如何工作?

4

1 回答 1

37

原型是一个普通的对象。当一个对象继承一个原型时,它不只是复制原型的属性,对象存储了对原型的引用。

没错,一个对象的原型,只是通过原型链引用的另一个对象。

你的两个片段之间的区别在于__proto__你正在改变food. 在您的第二个示例中,您只是分配了一个继承自的新对象more_food,这food.fruit就是解析为的原因undefined,因为您的原始food对象因该分配而丢失

Object.create 到底在做什么?

Object.create构建一个新对象,该对象继承自作为其第一个参数传递的对象(它只能是对象或null)。

变量 food 是分配了对原型 more_food 的引用,还是 Object.create 只是返回了对象 more_food 的副本?

您的food变量将包含一个新对象,该对象继承自more_food,此操作中没有任何复制。

例如:

var food = {fruit:"apple"};
var more_food = Object.create(food, {
  vegetable: { value: "celery" }
});

more_food.fruit;     // "apple"
more_food.vegetable; // "celery"

在上面的例子中,more_food继承自food,换句话说,food是 的原型more_food,这个原型引用存储在一个名为 的内部属性中[[Prototype]]。的第二个参数Object.create允许您初始化这个新对象的属性。

没有复制,只是上面例子中的普通委托more_food.fruit可以通过原型链访问,属性查找过程非常简单,如果在对象上没有找到属性,则在对象的原型上再次查找(委托!),递归地,直到找到其原型的对象null(如Object.prototype)。

所以,more_food.fruit是一个继承的属性:

more_food.hasOwnProperty('fruit'); // false, inherited
'fruit' in more_food;              // true

Whilevegetable是 的自有财产more_food

more_food.hasOwnProperty('vegetable'); // true

上面的示例在图形上看起来像这样:

  +----------+ [[原型]] +---------------+
  | more_food |+--------------->| 食品|
  |----------------------| |---------------|
  | 蔬菜:“芹菜” | | 水果:“苹果 |
  +----------+ +--------------+

如果 Object.create 只是制作一个副本,那么如果变量 food 没有引用 more_food,那么原型链是如何工作的呢?

Object.create不创建对象的副本,它只是在创建新对象时设置其原型。

请记住,这__proto__是一个非标准功能,将来会从实现中删除,在Mozilla 文档中已被列为已弃用,这是主要原因,这也是该语言可能永远无法使用的原因以允许你的方式改变原型链是它会导致优化和安全问题,在 VM 和 JIT 级别。__proto__

于 2011-11-01T05:58:41.357 回答