是否可以将其分解为现有对象?(JavaScript ES6)


135

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

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

var oof = {}

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

也许像这样:

oof{x,y} = foo

10
如果您想复制所有属性Object.assign(oof, foo)
elclanrs 2015年

在MDN上有很多破坏性的示例,但是我没有看到您要问的示例。
jfriend00 2015年

嗯,我无法找到一个既..
majorBummer

如果没有两行解决方案,请参见下面的答案Object.assign
-Zfalen

Answers:


115

虽然难看且有点重复,但您可以

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

虽然。


2
备选['x','y']。forEach(prop => oof [prop] = foo [prop]); 如我所见,是迄今为止唯一的一种DRY(请勿重复)。在要映射多个键的情况下,“ DRY”确实有用。您只需要更新一个地方。也许我错了。不管怎么说,还是要谢谢你!
弗拉基米尔·巴西

1
第三个示例是DRY,但是您必须使用字符串作为键,而javascript通常会隐式地执行此操作。不相信这比下面的麻烦少:const {x,y} = foo; const oof = {x,y};
杰夫·洛里

有人可以在jsfiddle中向我展示第一个建议的作用吗?在chrome上无法正常使用:jsfiddle.net/7mh399ow
techguy2000

@ techguy2000您忘记了分号var oof = {};
loganfsmyth

在第一个代码中,不应为({x: oof.x, y: oof.y} = foo)?我认为您在oof中加了一个额外的f
Sornii

38

不,解构不支持简写的成员表达式,而当前仅支持普通的属性名。目前已经谈关于这样的esdiscuss,但不建议将它做成ES6。

但是,您可能可以使用Object.assign-如果不需要所有自己的属性,则仍然可以使用

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

3
@loganfsmyth,至少在对节点4.2.2进行测试时,您的示例对我不起作用。与--harmony_destructuring启用。我看到“ SyntaxError:意外的令牌。”
jpierson

@loganfsmyth,您应该提交正确的答案,因为这是一个非常有用的注释imo。
Sulliwane '16

@Sulliwane:他已经做到了(现在)。Bergi,最好是更新答案以指出您可以使用Logan所示的成员表达式。(规格真的在2015年4月至2015年6月之间发生了很大变化吗?)
TJ Crowder

@TJCrowder不,我不认为它已经改变,我想我在说{oof.x, oof.y} = foo。也许我真的很想念它。
Bergi

29

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要求很多,我只需要离散数据几块。但是,我同意应该做到这一点。

编辑:PS- 我最近了解到,可以在第一步中使用超解构从复杂对象中拉出嵌套值!例如...

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 };

我喜欢这种方法,务实。
杰西

2
这是我要做的,但不是很干。我认为很多人真正需要的只是一个提取键功能。
jgmjgm

@jgmjgm是的,内置一个会很好,但是我想也不太难写。
Zfalen '18年

12

除了Object.assign存在物体传播语法这是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"
}
*/

但是要使用此功能,您需要使用Babel stage-2transform-object-rest-spread插件。这是关于Babel演示stage-2


9
这实际上并没有设置现有对象的属性,而是创建了一个包含两个属性的新对象。
马特·布朗

8

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

let myTest = { test1, test3 } = myObject;不起作用
Eatdoku


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
majorBummer

1
@majorBummer最后,您打电话给我,但是我会考虑不实际回答您问题的方法,因为它们都创建了对象,而不是像标题所要求的那样向现有对象添加属性。
loganfsmyth,

@loganfsmyth很好。我想我只是对campSafari提出的方法感到兴奋,因为我没有意识到这是可能的。
majorBummer

1
如果您不介意创建新对象,则可以做oof = {...oof, ...foo}
Joshua Coady

2

您可以通过箭头函数返回已分解的对象,然后使用Object.assign()将其分配给变量。

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

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

1

干燥

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})()});

1

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

工作示例:

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


0

这适用于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"
}

7
可悲的是,似乎oof只是收到了的引用,foo并绕过了整个销毁过程(至少在Chrome中是如此)。oof === foolet oof = { x } = foo返回{ x, y }
Theo.T 16/09/14

@ Theo.T好抓。那真是令人b目结舌,我将不得不寻找另一种方式
user1577390

值得一提的只是演示JS如何令人困惑。
jgmjgm

0

我想出了这种方法:

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您不同的是,您也可以同时重命名它们。

如果要将道具复制到现有对象上,只需设置destarg。


0

这是一种作弊行为,但您可以执行以下操作...

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' }

0

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

let props = { 
  isValidDate: 'yes',
  badProp: 'no!',
};

let { isValidDate } = props;
let newProps = { isValidDate };

console.log(newProps);

它将输出 { isValidDate: 'yes' }

将来有一天能够说些类似的话会很高兴,let newProps = ({ isValidDate } = props)但不幸的是,ES6不支持这种方式。


0

这不是一个漂亮的方法,我也不推荐这样做,但是这种方法可能只是为了获取知识。

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"}

0

您可以使用JSON类方法来实现它,如下所示

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

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

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

JSON.stringify的MDN文档

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.