告诉我,如果我错了:
原型是普通对象。当一个对象继承原型时,它不仅仅复制原型的属性,该对象存储对原型的引用。
在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
到底在做什么?变量食物是否分配了对原型more_food的引用,或者是Object.create只返回对象的副本more_food?如果Object.create
只是制作副本,那么如果变量食物没有引用more_food,原型链如何工作?
答案 0 :(得分:35)
原型是普通对象。当一个对象继承原型时,它不仅仅复制原型的属性,该对象存储对原型的引用。
你是对的,一个对象的原型,只是通过原型链引用的另一个对象。
您的两个片段之间的区别在于,__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
虽然vegetable
是more_food
的自有属性,但
more_food.hasOwnProperty('vegetable'); // true
上面的例子看起来像这样:
+---------------------+ [[Prototype]] +---------------+ | more_food |+--------------->| food | |---------------------| |---------------| | vegetable: "celery" | | fruit: "apple | +---------------------+ +---------------+
如果Object.create只是制作副本,那么如果变量食物没有引用more_food,原型链如何工作?
Object.create
不会创建对象的副本,它只是在创建新对象时设置原型。
请注意,__proto__
是非标准功能,将来会从实施中删除,已被列为已弃用在Mozilla Documentation上,这是主要原因,这也是为什么语言可能永远无法以__proto__
允许的方式改变原型链的原因,因为它会导致优化和安全问题, VM和JIT的级别。