首页 > 解决方案 > 关于 Object.create() 和属性继承的困惑

问题描述

在下面的代码段中,为什么boat.calls我打电话时会增加sailboat.getHasEngine()?另外,为什么sailboat.calls只调用一次 getHasEngine() 后设置为 2?

let vehicle = {
  calls: 0,
  hasEngine: null,
  getHasEngine: function() {
    vehicle.calls = vehicle.calls + 1;
    this.calls = this.calls + 1;
    return this.hasEngine;
  },
  canFly: null,
  getCanFly: function() { 
    vehicle.calls = vehicle.calls + 1;
    this.calls = this.calls + 1;
    return this.canFly; 
  }
}

let boat = Object.create(vehicle);
boat.canFly = false;

let sailboat = Object.create(boat);
sailboat.hasEngine = false;

let fishingBoat = Object.create(boat);
fishingBoat.hasEngine = true;

console.log(vehicle.calls);
// 0
console.log(boat.calls);
// 0
console.log(sailboat.calls);
// 0

sailboat.getHasEngine();

console.log(vehicle.calls);
// 1
console.log(boat.calls);
// 1
console.log(sailboat.calls);
// 2

标签: javascript

解决方案


因为这条线在getHasEngine

vehicle.calls = vehicle.calls + 1;

那就是直接访问vehicle对象。由于boat没有自己的calls属性,它从 继承vehicle,所以boat.calls是 1。

另外,为什么sailboat.calls只调用getHasEngine()一次后设置为2?

也因为那条线:它设置vehicle.calls1,并且此时sailboat没有自己的calls,因此它继承了该属性。然后在下一行执行:

this.calls = this.calls + 1;

那就是读取 vehicle.calls(1),将 1 添加到它,然后将结果 (2) 分配给sailboat.calls.

让我们向它扔一些 ASCII 艺术。在创建对象之后但在调用之前getHasEngine,您在内存中有这个(省略细节):

                                                          +−−−−−−−−−−−+
车辆−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− ->| (对象) |
                                                      | +−−−−−−−−−−−+
                                                      | | 来电:0 |
                                                      | +−−−−−−−−−−−+
                                   +−−−−−−−−−−−−−−−−+ |
船−−−−−−−−−−−−−−−−−−−−−−−−−−−−+−−>| (对象) | |
                               | +−−−−−−−−−−−−−−−−+ |
                               | | [[原型]] |−−+
                               | +−−−−−−−−−−−−−−−−−+     
                               |
            +−−−−−−−−−−−−−−−−+ |
帆船--->| (对象) | |
            +−−−−−−−−−−−−−−−−+ |
            | [[原型]] |−−+
            +−−−−−−−−−−−−−−−−−+      

请注意,既boat没有也没有sailboat属性calls

getHasEngine被调用一次之后,你就有了——注意sailboat现在有一个calls属性(因为它是由创建的this.calls = this.calls + 1;):

                                                          +−−−−−−−−−−−+
车辆−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− ->| (对象) |
                                                      | +−−−−−−−−−−−+
                                                      | | 来电:1 |
                                                      | +−−−−−−−−−−−+
                                   +−−−−−−−−−−−−−−−−+ |
船−−−−−−−−−−−−−−−−−−−−−−−−−−−−+−−>| (对象) | |
                               | +−−−−−−−−−−−−−−−−+ |
                               | | [[原型]] |−−+
                               | +−−−−−−−−−−−−−−−−−+     
                               |
            +−−−−−−−−−−−−−−−−+ |
帆船--->| (对象) | |
            +−−−−−−−−−−−−−−−−+ |
            | [[原型]] |−−+
            | 来电:2 |
            +−−−−−−−−−−−−−−−−−+      

这是一个带有一些日志记录的版本,以帮助说明这一点:

let vehicle = {
  calls: 0,
  hasEngine: null,
  getHasEngine: function() {
    console.log("updating vehicle.calls");
    vehicle.calls = vehicle.calls + 1;
    console.log("vehicle.calls is now vehicle.calls");
    console.log("About to update this.calls, does this have calls?", this.hasOwnProperty("calls"));
    this.calls = this.calls + 1;
    console.log("Just updated this.calls, does this have calls?", this.hasOwnProperty("calls"));
    return this.hasEngine;
  },
  canFly: null,
  getCanFly: function() { 
    vehicle.calls = vehicle.calls + 1;
    this.calls = this.calls + 1;
    return this.canFly; 
  }
}

let boat = Object.create(vehicle);
boat.canFly = false;

let sailboat = Object.create(boat);
sailboat.hasEngine = false;

let fishingBoat = Object.create(boat);
fishingBoat.hasEngine = true;

console.log(vehicle.calls);  // 0
console.log(boat.calls);     // 0
console.log("boat has calls?", boat.hasOwnProperty("calls"));
console.log(sailboat.calls); // 0
console.log("sailboat has calls?", sailboat.hasOwnProperty("calls"));

sailboat.getHasEngine();

console.log(vehicle.calls);  // 1
console.log(boat.calls);     // 1
console.log("boat has calls?", boat.hasOwnProperty("calls"));
console.log(sailboat.calls); // 2
console.log("sailboat has calls?", sailboat.hasOwnProperty("calls"));
.as-console-wrapper {
  max-height: 100% !important;
}

如果删除该vehicle.calls =行,您会看到它停止发生:

let vehicle = {
  calls: 0,
  hasEngine: null,
  getHasEngine: function() {
    //vehicle.calls = vehicle.calls + 1;
    this.calls = this.calls + 1;
    return this.hasEngine;
  },
  canFly: null,
  getCanFly: function() { 
    //vehicle.calls = vehicle.calls + 1;
    this.calls = this.calls + 1;
    return this.canFly; 
  }
}

let boat = Object.create(vehicle);
boat.canFly = false;

let sailboat = Object.create(boat);
sailboat.hasEngine = false;

let fishingBoat = Object.create(boat);
fishingBoat.hasEngine = true;

console.log(vehicle.calls);  // 0
console.log(boat.calls);     // 0
console.log(sailboat.calls); // 0

sailboat.getHasEngine();

console.log(vehicle.calls);  // 0
console.log(boat.calls);     // 0
console.log(sailboat.calls); // 1


推荐阅读