javascript - 关于 Object.create() 和属性继承的混淆

标签 javascript

在下面的代码片段中,为什么当我调用 sailboat.getHasEngine() 时,boat.calls 会增加?另外,为什么只调用一次 getHasEngine() 后 sailboat.calls 设置为 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

最佳答案

因为 getHasEngine 中的这一行:

vehicle.calls = vehicle.calls + 1;

这是直接访问vehicle对象。由于 boat 没有自己的 calls 属性,它继承自 vehicle,因此 boat.calls 是1.

Also, why is sailboat.calls set to 2 after only calling getHasEngine() once?

也因为这一行:它将 vehicle.calls 设置为 1,此时,sailboat 没有自己的调用,因此它继承了该属性。然后在下一行执行以下操作:

this.calls = this.calls + 1;

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

让我们给它添加一些 ASCII 艺术。创建对象之后、调用 getHasEngine 之前,内存中包含以下内容(省略详细信息):

                                                          +−−−−−−−−−−+
vehicle−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+−−>| (object) |
                                                      |   +−−−−−−−−−−+
                                                      |   | calls: 0 |
                                                      |   +−−−−−−−−−−+
                                   +−−−−−−−−−−−−−−−+  | 
boat−−−−−−−−−−−−−−−−−−−−−−−−−−−+−−>|   (object)    |  | 
                               |   +−−−−−−−−−−−−−−−+  | 
                               |   | [[Prototype]] |−−+ 
                               |   +−−−−−−−−−−−−−−−+     
                               |
            +−−−−−−−−−−−−−−−+  |
sailboat−−−>|   (object)    |  |
            +−−−−−−−−−−−−−−−+  |
            | [[Prototype]] |−−+
            +−−−−−−−−−−−−−−−+      

Note that neither boat nor sailboat has a calls property.

After getHasEngine is called once, you have this — note that sailboat now has a calls property (because it was created by this.calls = this.calls + 1;):

                                                          +−−−−−−−−−−+
vehicle−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+−−>| (object) |
                                                      |   +−−−−−−−−−−+
                                                      |   | calls: 1 |
                                                      |   +−−−−−−−−−−+
                                   +−−−−−−−−−−−−−−−+  | 
boat−−−−−−−−−−−−−−−−−−−−−−−−−−−+−−>|   (object)    |  | 
                               |   +−−−−−−−−−−−−−−−+  | 
                               |   | [[Prototype]] |−−+ 
                               |   +−−−−−−−−−−−−−−−+     
                               |
            +−−−−−−−−−−−−−−−+  |
sailboat−−−>|   (object)    |  |
            +−−−−−−−−−−−−−−−+  |
            | [[Prototype]] |−−+
            | calls: 2      |
            +−−−−−−−−−−−−−−−+      

Here's a version with some logging to help show that a bit:

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

关于javascript - 关于 Object.create() 和属性继承的混淆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53178062/

相关文章:

javascript - 在多个数组中复制一个对象数组

javascript - if 语句不起作用 jquery

javascript - 如何隐藏所有 Angular Material 选项卡的选项卡内容

javascript - 如何抓取即将上传的多个文件的名称?

javascript - angularjs 进度条动态宽度

javascript - 使用带有 JS 输入的 Header 下载文件

javascript - 重绘后 jQuery .mouseenter 不起作用

javascript - 如何在一个 div 中声明 ng-show 和 ng-hide

javascript - JS - 不错的类似 sleep 的功能

javascript - 使用js动态更改css类