【问题标题】:Why would you use the spread operator to spread a variable onto itself?为什么要使用扩展运算符将变量扩展到自身?
【发布时间】:2023-08-13 17:40:01
【问题描述】:

在 Google Getting started with Node.js 教程中他们执行以下操作

data = {...data};

在向 Firestore 发送数据的代码中。

你可以在their Github,第 63 行看到它。

据我所知,这没有任何作用。

这样做有充分的理由吗?

它是否有可能在未来进行验证,因此如果您添加自己的数据,您就不太可能执行data = {data, moreData} 之类的操作?

【问题讨论】:

    标签: node.js spread-syntax


    【解决方案1】:

    @Manu 的回答详细说明了什么代码行在做什么,但没有为什么它在那里。

    我不知道 Google 代码示例为何使用这种方法,但我猜想如下原因(在这种情况下我自己也会这样做):

    由于 JavaScript 中的对象是通过引用传递的,因此有必要从其组成部分重建“数据”对象,以避免原始数据对象被示例第 64 行的 ref.set(data) 调用进一步修改代码:

    await ref.set(data);
    

    例如,在 MongoDB 中,当您将对象传递给 write 或 update 方法时,Mongo 实际上会修改该对象以添加额外的属性,例如它被插入到集合中的日期时间或它在集合中的 ID。我不确定 Firestore 是否会这样做,但如果现在没有,将来可能会这样做。如果是这样,并且如果您从 Google 的示例代码调用 update 方法的原始代码继续进一步操作它最初传递的数据对象,那么该对象现在将具有可能导致意外问题的额外属性。因此,谨慎的做法是根据原始对象的属性重新构建数据对象,以避免在代码中的其他地方污染原始对象。

    我希望这是有道理的——我想得越多,我就越相信这一定是原因,这实际上是一个很好的学习点。


    我在此处包含 Google 代码中的完整原始函数,以防其他人将来遇到此问题,因为代码可能会更改(在撰写此答案时从 https://github.com/GoogleCloudPlatform/nodejs-getting-started/blob/master/bookshelf/books/firestore.js 复制):

    // Creates a new book or updates an existing book with new data.
    async function update(id, data) {
      let ref;
      if (id === null) {
        ref = db.collection(collection).doc();
      } else {
        ref = db.collection(collection).doc(id);
      }
    
      data.id = ref.id;
      data = {...data};
      await ref.set(data);
      return data;
    }
    

    【讨论】:

      【解决方案2】:

      它正在生成shallow copydata;假设您有一个改变输入的第三方函数:

      const foo = input => {
        input['changed'] = true;
      }
      

      你需要调用它,但又不想修改你的对象,所以而不是:

      data = {life: 42}
      foo(data)
      
      // > data
      // { life: 42, changed: true }
      

      您可以使用Spread Syntax:

      data = {life: 42}
      foo({...data})
      
      // > data
      // { life: 42 }
      

      不确定这是否是 Firestone 的特殊情况,但问题是:传播一个对象会得到该 obj 的浅表副本。

      ===

      相关:Object copy using Spread operator actually shallow or deep?

      【讨论】:

      • It's making a copy of data; 我可能会写 shallow copy 以表明没有进行深拷贝。
      • 您的相关链接似乎与您回答的第一部分相矛盾。 “如果没有嵌套,它会深度复制数据。对于嵌套数据,它会深度复制最顶层的数据和嵌套数据的浅层。”
      • 同样在这种情况下,它是什么样的副本似乎并不重要,因为新副本被分配给原始变量。所以没有一个新的变量可以对抗深/浅。