能否将解构赋值应用于现有对象?(JavaScript ES6)

185
例如,如果我有两个物体:
var foo = {
  x: "bar",
  y: "baz"
}

并且

var oof = {}

我想将foo中的x和y值转移到oof中。是否可以使用ES6的解构语法来实现这个目的?
也许可以尝试以下方式:
oof{x,y} = foo

11
如果你想要复制所有属性,可以使用 Object.assign(oof, foo) 这个方法。 - elclanrs
1
这里在MDN上有很多解构的例子,但我没有看到你所问的那个。 - jfriend00
1
哎呀,我也找不到一个。。 - tnrich
请看下面的答案,其中没有使用Object.assign的两行解决方案。 - Zfalen
17个回答

173

虽然不太美观且有些重复,但您可以做到

({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]);

虽然。


6
据我所见,['x', 'y'] 这种写法是到目前为止唯一符合 D.R.Y(不要重复自己)原则的写法。在需要映射多个键的情况下,“DRY”确实非常有用,只需要在一个地方更新即可。也许我错了,无论如何,感谢您! - Vladimir Brasil
2
第三个例子是DRY的,但你必须使用字符串作为键,而JavaScript通常会隐式地执行此操作。我并不认为这比以下代码更方便: const {x, y} = foo; const oof = {x, y}; - Jeff Lowery
在第一段代码中,不应该是 ({x: oof.x, y: oof.y} = foo) 吗?我认为你在 oof 中多加了一个 _f_。 - Sornii
@Sornii 谢谢,已修复! - loganfsmyth
我个人喜欢第一个示例的语法,当从一种大小写样式转换为另一种时,像这样:({ order_number: this.orderNumber, order_amount: this.orderAmount } = this.config); - Giorgio Tempesta
显示剩余6条评论

61
在我看来,这是实现你所寻求的最简单的方法:
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 };

我喜欢这种务实的方法。 - Jesse
2
这是我的做法,但不是很干燥。我认为许多人真正需要的只是提取键函数。 - jgmjgm
@jgmjgm 是的,内置一个会很好,但我猜写一个也不太难。 - Zfalen

42
不,解构不支持简写中的成员表达式,只支持当前时间的普通属性名。关于这个问题在ES Discuss上有所讨论,但是没有提案会被纳入ES6。
然而,你可能可以使用Object.assign。如果你不需要所有自有属性,你仍然可以这样做:
var foo = …,
    oof = {};
{
    let {x, y} = foo;
    Object.assign(oof, {x, y})
}

3
在我的测试中,即使启用了 --harmony_destructuring,你的示例在 Node 4.2.2 中也无法正常工作。我看到了 "SyntaxError: Unexpected token ." 的错误提示。请检查一下代码。 - jpierson
@loganfsmyth,我认为您应该提交一个正式的答案,因为这是一条非常有用的评论。 - Sulliwane
@Sulliwane: 他已经完成了。Bergi,最好更新答案并指出Logan所示的可以使用成员表达式。(规范在2015年4月和6月之间真的改变了这么多吗?) - T.J. Crowder
@T.J.Crowder 没有,我不认为它改变了,我想我当时在谈论 {oof.x, oof.y} = foo。或者也许我真的错过了。 - Bergi

14
除了Object.assign之外,还有对象展开语法,它是ECMAScript的第二阶段提案。

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

    var oof = { z: "z" }

    oof =  {...oof, ...foo }

    console.log(oof)

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

但是要使用这个功能,你需要在Babel中使用stage-2transform-object-rest-spread插件。这里有一个关于使用stage-2Babel演示

12
这实际上并没有在现有对象上设置属性,而是创建一个包含两者所有属性的新对象。 - Matt Browne

10

BabelJS 插件

如果您正在使用 BabelJS,现在可以激活我的插件 babel-plugin-transform-object-from-destructuring (请查看 npm 包以获取安装和使用说明).

我遇到了与此线程描述的相同问题,当您从解构表达式创建一个对象时,特别是当您必须重命名、添加或删除属性时,这会让人非常疲惫。通过此插件,维护此类情况将变得更加容易。

对象示例

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;

这正是我想要的。谢谢! - garrettmaring
2
let myTest = { test1, test3 } = myObject; 不起作用。 - Eatdoku

4

3
您可以使用重构来实现这个目的,像这样:

您只需这样做:

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 - tnrich
1
@majorBummer 最终决定权在你手中,但我认为不应该回答你的问题,因为这两种方法都会创建_新_对象,而不是像你的标题所要求的那样向_现有_对象添加属性。 - loganfsmyth
这是个好观点@loganfsmyth。我认为我只是被campSafari提出的方法所激动,因为我之前没有意识到那是可能的。 - tnrich
1
如果您不介意创建一个新对象,您可以直接执行 oof = {...oof, ...foo} - Joshua Coady
@JoshuaCoady ...= 运算符什么时候使用? - Ecksters

2
你可以通过直接分配到另一个对象属性来销毁一个对象。
工作示例:

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


你可以直接将一个对象属性赋值给另一个对象属性来销毁一个对象。在你的第一个例子中,你是对一个数组进行解构赋值,而不是一个对象。 - Austin France

2

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

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

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

1

Try

    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({...(() => ({a1, a2, b1, b2})).bind({...a, ...b})()});


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接