javascript - 关于 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
解决方案
因为这条线在getHasEngine
:
vehicle.calls = vehicle.calls + 1;
那就是直接访问vehicle
对象。由于boat
没有自己的calls
属性,它从 继承vehicle
,所以boat.calls
是 1。
另外,为什么
sailboat.calls
只调用getHasEngine()
一次后设置为2?
也因为那条线:它设置vehicle.calls
为1
,并且此时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
推荐阅读
- node.js - 使用不同参数的猫鼬查询
- vue.js - 使用 nuxt、vuex 和 jest gettig 测试 vue 应用程序不支持错误
- laravel - 在 findOrFail 错误消息中自定义 ExceptionHandler
- java - 将一行附加到现有文本文件但添加一个额外的空白行
- regex - 如何匹配我的特定主题标签模式?
- for-loop - 无法使用 Beautiful Soup 在 python 中循环 bs4.element.ResultSet 类型
- java - Java RSA 解密 - 错误填充异常
- kubernetes - nats流集群如何连接
- python - python aiohttp 客户端响应对象到 io.Text IO Wrapper
- azure-functions - Azure 函数 CosmosDB function.json