8.1 原型继承

for..in 循环也会迭代继承的属性。

  1. let animal = {
  2. eats: true,
  3. };
  4. let rabbit = {
  5. jumps: true,
  6. __proto__: animal,
  7. };
  8. // Object.keys 只返回自己的 key
  9. alert(Object.keys(rabbit)); // jumps
  10. // for..in 会遍历自己以及继承的键
  11. for (let prop in rabbit) alert(prop); // jumps,然后是 eats

几乎所有其他键/值获取方法,例如 Object.keys 和 Object.values 等,都会忽略继承的属性。
它们只会对对象自身进行操作。不考虑 继承自原型的属性。

在现代引擎中,从性能的角度来看,我们是从对象还是从原型链获取属性都是没区别的。它们(引擎)会记住在哪里找到的该属性,并在下一次请求中重用它。

  1. // this.stomach= 不会执行对 stomach 的查找。该值会被直接写入 this 对象。
  2. // this.stomach.push(food); 会
  3. let hamster = {
  4. stomach: [],
  5. eat(food) {
  6. this.stomach.push(food);
  7. },
  8. };
  9. let speedy = {
  10. __proto__: hamster,
  11. };
  12. let lazy = {
  13. __proto__: hamster,
  14. };
  15. // 这只仓鼠找到了食物
  16. speedy.eat("apple");
  17. alert(speedy.stomach); // apple
  18. // 这只仓鼠也找到了食物,为什么?请修复它。
  19. alert(lazy.stomach); // apple

8.2 F.prototype

F.prototype 属性仅在 new F 被调用时使用,它为新对象的 [[Prototype]] 赋值。

  1. let animal = {
  2. eats: true,
  3. };
  4. function Rabbit(name) {
  5. this.name = name;
  6. }
  7. Rabbit.prototype = animal;
  8. let rabbit = new Rabbit("White Rabbit"); // rabbit.__proto__ == animal
  9. alert(rabbit.eats); // true

每个函数都有 “prototype” 属性,即使我们没有提供它。
默认的 “prototype” 是一个只有属性 constructor 的对象,属性 constructor 指向函数自身。

  1. function Rabbit(name) {
  2. this.name = name;
  3. alert(name);
  4. }
  5. let rabbit = new Rabbit("White Rabbit");
  6. let rabbit2 = new rabbit.constructor("Black Rabbit");

注意,当 prototype 被修改,constructor 可能就不存在了

8.4 现代原型方法

设置和直接访问原型的现代方法有:
Object.create(proto, [descriptors]) —— 利用给定的 proto 作为 [[Prototype]](可以是 null)和可选的属性描述来创建一个空对象。
Object.getPrototypeOf(obj) —— 返回对象 obj 的 [[Prototype]](与 proto 的 getter 相同)。
Object.setPrototypeOf(obj, proto) —— 将对象 obj 的 [[Prototype]] 设置为 proto(与 proto 的 setter 相同)。

  1. let animal = {
  2. eats: true,
  3. };
  4. // 创建一个以 animal 为原型的新对象
  5. let rabbit = Object.create(animal);
  6. alert(rabbit.eats); // true
  7. alert(Object.getPrototypeOf(rabbit) === animal); // true
  8. Object.setPrototypeOf(rabbit, {}); // 将 rabbit 的原型修改为 {}