【问题标题】:Is it possible to destructure onto an existing object? (Javascript ES6)是否可以解构到现有对象? (Javascript ES6)
【发布时间】:2015-06-19 16:05:06
【问题描述】:

例如,如果我有两个对象:

var foo = {
  x: "bar",
  y: "baz"
}

var oof = {}

我想将 x 和 y 值从 foo 转移到 oof。有没有办法使用 es6 解构语法来做到这一点?

可能是这样的:

oof{x,y} = foo

【问题讨论】:

  • 如果要复制所有属性Object.assign(oof, foo)
  • 很多破坏性的例子here on MDN,但我没有看到你要问的那个。
  • 嗯我也找不到..
  • 在下面查看我的答案,了解没有Object.assign的两行解决方案

标签: javascript ecmascript-6 destructuring


【解决方案1】:

虽然丑陋且有点重复,但您可以这样做

({x: oof.x, y: oof.y} = foo);

它将读取foo 对象的两个值,并将它们写入oof 对象上各自的位置。

个人还是比较喜欢看的

oof.x = foo.x;
oof.y = foo.y;

['x', 'y'].forEach(prop => oof[prop] = foo[prop]);

虽然。

【讨论】:

  • 另一种选择 ['x', 'y'].forEach(prop => oof[prop] = foo[prop]);如我所见,是唯一一个 D.R.Y(不要重复自己),直到现在。在要映射多个键的情况下,“DRY”确实很有用。您只需要更新一个地方。也许我错了。还是谢谢!
  • 第三个例子是 DRY,但你必须使用字符串作为键,javascript 通常会隐式执行。不相信这比: const {x, y} = foo; const oof = {x, y};
  • 有人可以在 jsfiddle 中告诉我第一个建议在哪里起作用吗?它不适用于 chrome:jsfiddle.net/7mh399ow
  • @techguy2000 你忘了var oof = {};后面的分号。
  • 在第一个代码中,不应该是({x: oof.x, y: oof.y} = foo) 吗?我认为您在 oof 中添加了一个额外的 f
【解决方案2】:

IMO 这是完成您所寻找的最简单的方法:

let { prop1, prop2, prop3 } = someObject;
let data = { prop1, prop2, prop3 };

  // data === { prop1: someObject.prop1, ... }

基本上,解构为变量,然后使用初始化程序简写来创建一个新对象。不需要Object.assign

无论如何,我认为这是最易读的方式。您可以在此从someObject 中选择您想要的确切道具。如果您有一个现有对象只想将道具合并到其中,请执行以下操作:

let { prop1, prop2, prop3 } = someObject;
let data = Object.assign(otherObject, { prop1, prop2, prop3 });
    // Makes a new copy, or...
Object.assign(otherObject, { prop1, prop2, prop3 });
    // Merges into otherObject

另一种可以说是更简洁的写法是:

let { prop1, prop2, prop3 } = someObject;
let newObject = { prop1, prop2, prop3 };

// Merges your selected props into otherObject
Object.assign(otherObject, newObject);

我将它用于POST 请求很多,我只需要几条离散数据。但是,我同意应该有一个单行来执行此操作。

编辑:P.S. - 我最近了解到您可以在第一步中使用超解构从复杂对象中提取嵌套值!比如……

let { prop1, 
      prop2: { somethingDeeper }, 
      prop3: { 
         nested1: {
            nested2
         } 
      } = someObject;
let data = { prop1, somethingDeeper, nested2 };

另外,您可以在创建新对象时使用扩展运算符而不是 Object.assign:

const { prop1, prop2, prop3 } = someObject;
let finalObject = {...otherObject, prop1, prop2, prop3 };

或者……

const { prop1, prop2, prop3 } = someObject;
const intermediateObject = { prop1, prop2, prop3 };
const finalObject = {...otherObject, ...intermediateObject };

【讨论】:

  • 我喜欢这种做法,务实。
  • 这是我做的,但不是很干。我认为很多人真正需要的只是一个提取键功能。
  • @jgmjgm 是的,内置一个会很好,但我想这也不太难写。
【解决方案3】:

不,解构不支持简写形式的成员表达式,但当前仅支持普通属性名。 esdiscuss 上有 have been talks 这样的内容,但没有提案会进入 ES6。

您也许可以使用 Object.assign 但是 - 如果您不需要所有自己的属性,您仍然可以这样做

var foo = …,
    oof = {};
{
    let {x, y} = foo;
    Object.assign(oof, {x, y})
}

【讨论】:

  • @loganfsmyth,您的示例至少在我使用节点 4.2.2 的测试中对我不起作用。启用--harmony_destructuring。我看到“SyntaxError: Unexpected token 。”
  • @loganfsmyth 你应该提交一个正确的答案,因为这是一个非常有用的评论 imo。
  • @Sulliwane:He's done so (now)。 Bergi,可能最好更新答案,指出您可以使用 Logan 所示的成员表达式。 (规范在 2015 年 4 月到 6 月之间发生了如此大的变化,真的吗?)
  • @T.J.Crowder 不,我认为它没有改变,我想我说的是{oof.x, oof.y} = foo。或许我真的错过了。
【解决方案4】:

除了Object.assign,还有object spread syntax,这是 ECMAScript 的第 2 阶段提案。

    var foo = {
      x: "bar",
      y: "baz"
    }
    
    var oof = { z: "z" }
    
    oof =  {...oof, ...foo }
    
    console.log(oof)

    /* result 
    {
      "x": "bar",
      "y": "baz",
      "z": "z"
    }
    */

但是要使用这个功能,你需要使用stage-2transform-object-rest-spread babel 插件。这是demo on babel with stage-2

【讨论】:

  • 这实际上并不设置现有对象的属性,而是创建一个包含两者所有属性的新对象。
【解决方案5】:

BabelJS 插件

如果您使用的是BabelJS,您现在可以激活我的插件babel-plugin-transform-object-from-destructuring (see npm package for installation and usage)。

我遇到了这个线程中描述的相同问题,对我来说,当您从解构表达式创建对象时非常累人,尤其是当您必须重命名、添加或删除属性时。使用此插件,您可以更轻松地维护此类场景。

对象示例

let myObject = {
  test1: "stringTest1",
  test2: "stringTest2",
  test3: "stringTest3"
};
let { test1, test3 } = myObject,
  myTest = { test1, test3 };

可以写成:

let myTest = { test1, test3 } = myObject;

数组示例

let myArray = ["stringTest1", "stringTest2", "stringTest3"];
let [ test1, , test3 ] = myArray,
  myTest = [ test1, test3 ];

可以写成:

let myTest = [ test1, , test3 ] = myArray;

【讨论】:

  • 这正是我想要的。谢谢!
  • let myTest = { test1, test3 } = myObject; 不起作用
【解决方案6】:

完全有可能。只是没有在一个声明中。

var foo = {
    x: "bar",
    y: "baz"
};
var oof = {};
({x: oof.x, y: oof.y} = foo); // {x: "bar", y: "baz"}

(请注意语句周围的括号。) 但请记住,易读性比代码打高尔夫球更重要:)。

来源:http://exploringjs.com/es6/ch_destructuring.html#sec_assignment-targets

【讨论】:

    【解决方案7】:

    你可以像这样使用重组:

    const foo = {x:"a", y:"b"};
    const {...oof} = foo; // {x:"a", y:"b"} 
    

    如果 oof 有值,则合并两个对象:

    const foo = {x:"a", y:"b"};
    let oof = {z:"c"}
    oof = Object.assign({}, oof, foo)
    

    【讨论】:

    • 我认为第一个案例正是我想要的。我在 chrome 控制台中尝试了它,它似乎可以工作。干杯! @campsafari
    • @majorBummer 最后是您的电话,但我会考虑实际上不回答您的问题的方法,因为它们都创建 new 对象,而不是向 现有的对象,如您的标题所要求的。
    • 这是一个很好的观点@loganfsmyth。我想我只是对 campSafari 提出的方法感到兴奋,因为我没有意识到这是可能的。
    • 如果你不介意创建一个新对象,你可以这样做oof = {...oof, ...foo}
    • @JoshuaCoady ...= 运营商何时?
    【解决方案8】:

    您可以在箭头函数中返回解构后的对象,并使用 Object.assign() 将其分配给变量。

    const foo = {
      x: "bar",
      y: "baz"
    }
    
    const oof = Object.assign({}, () => ({ x, y } = foo));
    

    【讨论】:

      【解决方案9】:

      您可以破坏直接分配给另一个对象属性的对象。

      工作示例:

      let user = {};
      [user.name, user.username] = "Stack Overflow".split(' ');
      document.write(`
      1st attr: ${user.name} <br /> 
      2nd attr: ${user.username}`);

      您可以使用与要捕获的对象属性同名的变量进行破坏,这样您就不需要这样做了:

      let user = { name: 'Mike' }
      let { name: name } = user;
      

      这样使用:

      let user = { name: 'Mike' }
      let { name } = user;
      

      如果对象结构具有相同的属性名称,您可以为它们设置新值。

      看看这个工作示例:

      // The object to be destructed
      let options = {
        title: "Menu",
        width: 100,
        height: 200
      };
      
      // Destructing
      let {width: w, height: h, title} = options;
      
      // Feedback
      document.write(title + "<br />");  // Menu
      document.write(w + "<br />");      // 100
      document.write(h);                 // 200

      【讨论】:

        【解决方案10】:

        试试

            var a = {a1:1, a2: 2, a3: 3};
            var b = {b1:1, b2: 2, b3: 3};
            
            const newVar = (() => ({a1, a2, b1, b2})).bind({...a, ...b});
            const val = newVar();
            console.log({...val});
            // print: Object { a1: 1, a2: 2, b1: 1, b2: 2 }

            console.log({...(() =&gt; ({a1, a2, b1, b2})).bind({...a, ...b})()});

        【讨论】:

          【解决方案11】:

          我想出了这个方法:

          exports.pick = function pick(src, props, dest={}) {
              return Object.keys(props).reduce((d,p) => {
                  if(typeof props[p] === 'string') {
                      d[props[p]] = src[p];
                  } else if(props[p]) {
                      d[p] = src[p];
                  }
                  return d;
              },dest);
          };
          

          你可以这样使用:

          let cbEvents = util.pick(this.props.events, {onFocus:1,onBlur:1,onCheck:'onChange'});
          let wrapEvents = util.pick(this.props.events, {onMouseEnter:1,onMouseLeave:1});
          

          也就是说,你可以选择你想要的属性并将它们放入一个新对象中。与_.pick 不同,您还可以同时重命名它们。

          如果您想将道具复制到现有对象上,只需设置 dest arg。

          【讨论】:

            【解决方案12】:

            这是一种作弊,但你可以这样做......

            const originalObject = {
              hello: 'nurse',
              meaningOfLife: 42,
              your: 'mom',
            };
            
            const partialObject = (({ hello, your }) => {
              return { hello, your };
            })(originalObject);
            
            console.log(partialObject); // ​​​​​{ hello: 'nurse', your: 'mom' }​​​​​
            

            在实践中,我认为您很少想要使用它。以下内容更加清晰......但几乎没有那么有趣。

            const partialObject = {
              hello: originalObject.hello,
              your: originalObject.your,
            };
            

            另一条完全不同的路线,包括与原型混搭(现在小心...):

            if (!Object.prototype.pluck) {
              Object.prototype.pluck = function(...props) {
                return props.reduce((destObj, prop) => {
                  destObj[prop] = this[prop];
            
                  return destObj;
                }, {});
              }
            }
            
            const originalObject = {
              hello: 'nurse',
              meaningOfLife: 42,
              your: 'mom',
            };
            
            const partialObject2 = originalObject.pluck('hello', 'your');
            
            console.log(partialObject2); // { hello: 'nurse', your: 'mom' }
            

            【讨论】:

              【解决方案13】:

              这是我能想到的最易读和最短的解决方案:

              let props = { 
                isValidDate: 'yes',
                badProp: 'no!',
              };
              
              let { isValidDate } = props;
              let newProps = { isValidDate };
              
              console.log(newProps);
              

              它将输出{ isValidDate: 'yes' }

              有朝一日能够说类似let newProps = ({ isValidDate } = props) 的东西会很好,但不幸的是,它不支持 ES6。

              【讨论】:

                【解决方案14】:

                可以使用JSON类方法实现如下

                const foo = {
                   x: "bar",
                   y: "baz"
                };
                
                const oof = JSON.parse(JSON.stringify(foo, ['x','y']));
                // output -> {x: "bar", y: "baz"}
                

                将需要添加到结果对象的属性作为第二个参数以数组格式传递给stringify 函数。

                MDN Doc for JSON.stringify

                【讨论】:

                  【解决方案15】:

                  这适用于 chrome 53.0.2785.89

                      let foo = {
                        x: "bar",
                        y: "baz"
                      };
                      
                      let oof = {x, y} = foo;
                      
                      console.log(`oof: ${JSON.stringify(oof)}`);
                      
                      //prints oof: { "x": "bar", "y": "baz"}

                  【讨论】:

                  • 可悲的是,oof 似乎只是收到了foo 的引用并绕过了整个解构(至少在 Chrome 中)。 oof === foolet oof = { x } = foo 却返回 { x, y }
                  • @Theo.T 不错。太丢人了,我得另谋出路
                  • 这些值得保留,只是为了展示 JS 是如何令人困惑的。
                  • 这适用于我测试的每个浏览器,但似乎不适用于 Babel/Webpack。
                  【解决方案16】:

                  这不是一个漂亮的方式,我也不推荐它,但是这种方式是可能的,只是为了知识。

                     const myObject = {
                        name: 'foo',
                        surname: 'bar',
                        year: 2018
                      };
                  
                      const newObject = ['name', 'surname'].reduce(
                        (prev, curr) => (prev[curr] = myObject[curr], prev),
                        {},
                      );
                  
                      console.log(JSON.stringify(newObject)); // {"name":"foo","surname":"bar"}

                  【讨论】:

                    猜你喜欢
                    • 2015-11-28
                    • 2020-04-12
                    • 2021-05-09
                    • 1970-01-01
                    • 2016-05-17
                    • 2020-04-26
                    • 1970-01-01
                    • 2019-05-28
                    相关资源
                    最近更新 更多