仅复制对象一部分的优雅方式

IT技术 javascript javascript-objects
2021-03-10 07:05:33

我想从一个更大的对象创建一个新对象,只复制它的几个属性。我知道的所有解决方案都不是很优雅,我想知道是否有更好的选择,如果可能的话,原生(没有像下面代码末尾那样的附加功能)?

这是我现在通常做的事情:

// I want to keep only x, y, and z properties:
let source = {
    x: 120,
    y: 200,
    z: 150,
    radius: 10,
    color: 'red',
};

// 1st method (not elegant, especially with even more properties):
let coords1 = {
    x: source.x,
    y: source.y,
    z: source.z,
};

// 2nd method (problem: it pollutes the current scope):
let {x, y, z} = source, coords2 = {x, y, z};

// 3rd method (quite hard to read for such simple task):
let coords3 = {};
for (let attr of ['x','y','z']) coords3[attr] = source[attr];

// Similar to the 3rd method, using a function:
function extract(src, ...props) {
    let obj = {};
    props.map(prop => obj[prop] = src[prop]);
    return obj;
}
let coords4 = extract(source, 'x', 'y', 'z');
6个回答

一种方法是通过对象解构和箭头函数:

let source = {
    x: 120,
    y: 200,
    z: 150,
    radius: 10,
    color: 'red',
};

let result = (({ x, y, z }) => ({ x, y, z }))(source);

console.log(result);

其工作方式(({ x, y, z }) => ({ x, y, z }))是立即使用source作为参数调用箭头函数它解构sourcexyz,然后立即将它们作为新对象返回。

如果颜色将是具有某些键值对的另一个对象并且我们需要访问它们,我们如何使用相同的颜色。
2021-04-30 07:05:33

只需要一个函数。

const extract = ({ x, y, z }) => ({ x, y, z });

let source = { x: 120, y: 200, z: 150, radius: 10, color: 'red' };

console.log(extract(source));

另一种解决方案是对具有目标属性的目标对象进行解构。

let source = { x: 120, y: 200, z: 150, radius: 10, color: 'red' }, 
    target = {};

({ x: target.x, y: target.y, z: target.z } = source);

console.log(target);

您可以通过Spread Operator执行如下操作

let source = {
    x: 120,
    y: 200,
    z: 150,
    radius: 10,
    color: 'red',
};

let {radius, color, ...newObj} = source;
console.log(newObj);

这是一个“省略”而不是“选择”:)
2021-05-04 07:05:33
不是我所期望的,但我学到了一个不错的功能!
2021-05-13 07:05:33
@trincot 感谢您的评论并注意到目的。再次感谢!
2021-05-14 07:05:33
如果要排除的属性已知且数量不多,则很方便!(+1)
2021-05-17 07:05:33

可能有解构的 IIFE?:

const coords = (({x, y, z}) => ({x, y, z}))(source);

对于像这样的简单情况,其他答案中提到的对象解构非常简洁,但在处理更大的结构时,当您将属性名称加倍时,往往看起来有点麻烦。

扩展您自己的答案 - 如果您打算编写一个extract实用程序(为了好玩,我会自己编写一个)……您可以通过对其进行柯里化来使其更加灵活 - 允许您交换参数的顺序(特别是将数据源最后),同时在接受属性名称时仍然是可变参数。

我认为这个签名extract = (...props) => src => { ... } 更优雅,因为它允许在编写新的命名函数时有更大程​​度的重用:

const extract = (...props) => src => 
    Object.entries(src).reduce(
        (obj, [key, val]) => (
            props.includes(key) && (obj[key] = val), 
            obj
    ), {})

const getCoords = extract('x', 'y', 'z')

const source = {
    x: 120,
    y: 200,
    z: 150,
    radius: 10,
    color: 'red'
}

console.log(getCoords(source))