仅复制 JavaScript 中选定属性的最短方法是什么?

What's the shortest way to copy only selected attributes in JavaScript?

给定以下两个对象:

let a = { foo: 'bar' };

let b = {
  one: 1,
  two: 2,
  three: 3,
  four: 4,
  five: 5,
  six: 6,
  seven: 7
};

我们可以假设这些对象中的所有值都是原始值。目标是将对象 b 中的 一些 属性复制到对象 a,但不是全部。

示例:

a.one = b.one;
a.two = b.two;
// Do not copy item three
a.four = b.four;
a.five = b.five;
a.six = b.six;
// Do not copy item seven

在此示例中,我们省略了属性 3 和 7,但我们也可以省略任何其他属性,甚至不止两个项目。如您所见,如果我们要处理许多属性,此解决方案可能会非常麻烦。

问题:什么是最短,最干净和最简单的解决方案来实现类似这与现代 JavaScript 在 2021 年?

注意:对于解决方案,您可以假设给出了一个字符串数组。每个字符串表示应复制的值的键。因此,在上面的示例中,您可以假设给出 const keys = ['one', 'two', 'four', 'five', 'six'];

这就是我的解决方案。即使它有效,我也不喜欢必须导入依赖项。想知道是否有更好的现代 JavaScript.

内置解决方案

util.js

export function copySelected(a, b, attrs) {
  for (let i=0; i < attrs.length; i+=1) {
    const attr = attrs[i];
    a[attr] = b[attr];
  }
  return a;
}

用法:

import { copySelected } from './util';

let a = { foo: 'bar' };

let b = {
  one: 1,
  two: 2,
  three: 3,
  four: 4,
  five: 5,
  six: 6,
  seven: 7
};

copySelected(a, b, ['one', 'two', 'four', 'five', 'six']);

我会在给定键的数组上使用 forEach 来复制我需要的内容:

const a = {
  foo: 'bar'
};

const b = {
  one: 1,
  two: 2,
  three: 3,
  four: 4,
  five: 5,
  six: 6,
  seven: 7
};

const doCopy = ['two', 'five'];

doCopy.forEach(el => a[el] = b[el]);

console.log(a);

查看评论:

const keys = ['one', 'two', 'four', 'five', 'six'];

let a = { foo: 'bar' };

let b = {
  one: 1,
  two: 2,
  three: 3,
  four: 4,
  five: 5,
  six: 6,
  seven: 7
};

// Loop over the array
keys.forEach(function(key){
  // If the b object contains the key specified in the array
  if(b[key]){
    a[key] = b[key];  // copy that key to a
  }
});

console.log(a);

与@Timo 的答案相同的想法,但具有映射函数和展开运算符。

function copySelected(a, b, ...attrs) {
  attrs.map(x => a[x] = b[x]);
  return a;
}

let a = { foo: 'bar' };

let b = {
  one: 1,
  two: 2,
  three: 3,
  four: 4,
  five: 5,
  six: 6,
  seven: 7
};

console.log( copySelected(a, b, 'one', 'two', 'four', 'five', 'six'));

这是一个 ECMAScript 2021 示例:

const b = {
  one: 1,
  two: 2,
  three: 3,
  four: 4,
  five: 5,
  six: 6,
  seven: 7
};

const copyFromThis = ['one','two']

const temp = Object.fromEntries(Object.entries(b).filter(([key , value])=>copyFromThis.includes(key) ))

console.log(temp)

您可以根据需要自定义它!

您可以使用 Object.assign 添加从 ba 的过滤条目(使用 keys 数组过滤 key/value 对):

const a = {
  foo: 'bar'
};

const b = {
  one: 1,
  two: 2,
  three: 3,
  four: 4,
  five: 5,
  six: 6,
  seven: 7
};

const keys = ['one', 'two', 'four', 'five', 'six'];

const res = Object
  .assign(a, Object.fromEntries(Object.entries(b)
    .filter(([k, v]) => keys.includes(k))
  ))
  
console.log(res)

您可以分配想要的属性。

a) 没有用于赋值的数组

let a = { foo: 'bar' },
    b = { one: 1, two: 2, three: 3, four: 4, five: 5, six: 6, seven: 7 },
    keys = ['one', 'two', 'four', 'five', 'six'];

keys.forEach(k => Object.assign(a, { [k]: b[k] }));

console.log(a);

b) 用数组赋值

let a = { foo: 'bar' },
    b = { one: 1, two: 2, three: 3, four: 4, five: 5, six: 6, seven: 7 },
    keys = ['one', 'two', 'four', 'five', 'six'];

Object.assign(a, ...keys.map(k => ({ [k]: b[k] })));

console.log(a);

最简单(也是最短)的可能还是一个循环:

const res = {};
for (const key of keys) res[key] = source[key];

你也可以这样写 reduce:

const res = keys.reduce((target, key) => { target[key] = source[key]; return target }, {});
const res = keys.reduce((target, key) => Object.assign(target, {[key]: source[key]}), {});

或者,更优雅地使用 Object.fromEntries:

const res = Object.fromEntries(keys.map(key => [key, source[key]]));

(但这不支持分配给现有对象)。