javascript - 当对象在另一个对象中返回时, setter/getter 会消失吗?

标签 javascript object

我正在编写游戏战舰代码,并为 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/

相关文章:

php - 将 JSON 数据从 Javascript 发送到 PHP?

Javascript 数组操作 - 是否有更具声明性的方法?

javascript - 自定义类中的原生JS : "Uncaught TypeError: Cannot set property ' innerHTML' of undefined"

javascript - 通过键删除嵌套结构中的对象

javascript - 一个简单的 Solidity 合约和脚本的无效操作码错误

javascript - Node JS 中的外部 CSS

javascript - 这个函数式 Javascript 示例如何工作?

javascript - 在单个命名空间下组合 javascript 伪类对象

Javascript ES6 解构嵌套对象父级和子级分配变量

javascript - 将数组从 PHP 返回到 JavaScript,无需 JSON