我正在编写游戏战舰代码,并为 Ship
工厂函数编写了以下代码:
const Ship = (len) => {
const length = len;
let _hitNumber = 0;
const hit = () => {
_hitNumber = _hitNumber + 1;
return _hitNumber
};
return {
length,
get hitNumber() {
return _hitNumber;
},
hit,
};
};
const ship = Ship(3);
ship.hit();
console.log(ship.hitNumber);
它按预期工作。如果我调用 hit()
然后检查 .hitNumber
它已经增加了。然后我创建了一个 Fleet
工厂,如下所示。它返回一个船舶数组:
const Ship = (len) => {
const length = len;
let _hitNumber = 0;
const hit = () => {
_hitNumber = _hitNumber + 1;
return _hitNumber
};
return {
length,
get hitNumber() {
return _hitNumber;
},
hit,
};
};
const Fleet = () => {
return [{
name: "Carrier",
...Ship(5),
},
{
name: "Battleship",
...Ship(4),
},
]
}
const testFleet = Fleet();
testFleet[0].hit();
console.log(testFleet[0].hitNumber)
但是现在调用 hit
不起作用:
就好像 .hitNumber
不再是 getter,或者 testFleet[0].hit()
不再引用 testFleet[0]
code> 的 _hitnumber
。
我希望帮助您了解发生了什么以及是数组括号还是扩展运算符负责。我怀疑 this article 中概述的陷阱是相关的,但我的情况足够不同(而且我的理解足够浅),我无法完全建立联系。
最佳答案
在您的 Ship()
函数中,您返回一个带有 getter 的对象,然后您稍后使用扩展运算符将船舶的所有属性复制到一个新对象。
在幕后, setter/getter 是调用 Object.defineProperty()
的语法糖。 。 Object.defineProperty()
可以对属性进行特殊设置,例如在访问属性时调用函数(这是一个 getter)。
但是,展开运算符只是将属性从一个对象复制到另一个对象,而不会复制 Object.defineProperty()
设置的特殊设置。因此,当展开运算符尝试复制 hitNumber
属性时,它会调用 getter 一次并复制结果,而不是函数本身。
要解决此问题,您需要实现自己的扩展运算符的替换,该运算符可以复制访问器(getter 和 setter)。幸运的是,这个问题很常见,MDN 提供了一个功能 in the documentation for Object.assign()
。这是您的代码的示例:
// from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#copying_accessors
function completeAssign(target, ...sources) {
sources.forEach((source) => {
const descriptors = Object.keys(source).reduce((descriptors, key) => {
descriptors[key] = Object.getOwnPropertyDescriptor(source, key);
return descriptors;
}, {});
Object.getOwnPropertySymbols(source).forEach((sym) => {
const descriptor = Object.getOwnPropertyDescriptor(source, sym);
if (descriptor.enumerable) {
descriptors[sym] = descriptor;
}
});
Object.defineProperties(target, descriptors);
});
return target;
}
const Ship = (len) => {
const length = len;
let _hitNumber = 0;
const hit = () => {
_hitNumber = _hitNumber + 1;
return _hitNumber
};
return {
length,
get hitNumber() {
return _hitNumber;
},
hit,
};
};
const Fleet = () => {
const arr = [{
name: "Carrier",
len: 5,
},
{
name: "Battleship",
len: 5,
},
];
arr.forEach(obj => {
completeAssign(obj, Ship(obj.len));
});
return arr;
}
const fleet = Fleet();
fleet[0].hit();
console.log(fleet[0].hitNumber);
关于javascript - 当对象在另一个对象中返回时, setter/getter 会消失吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74257880/