【问题标题】:Elegant way to copy only a part of an object [duplicate]仅复制对象的一部分的优雅方式[重复]
【发布时间】:2018-12-22 18:16:25
【问题描述】:

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

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

// 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');

【问题讨论】:

    标签: javascript javascript-objects


    【解决方案1】:

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

    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 作为参数调用。它将source 解构为xyz,然后立即将它们作为新对象返回。

    【讨论】:

    • 如果颜色将是另一个具有一些键值对的对象并且我们需要访问它们,我们如何使用相同的对象。
    【解决方案2】:

    只取一个函数。

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

    【讨论】:

      【解决方案3】:

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

      let source = {
          x: 120,
          y: 200,
          z: 150,
          radius: 10,
          color: 'red',
      };
      
      let {radius, color, ...newObj} = source;
      console.log(newObj);

      【讨论】:

      • 不是我所期望的,但我学到了一个不错的功能!
      • 如果要排除的属性已知且不多,则很方便! (+1)
      • @trincot 感谢您的评论并注意到目的。再次感谢!
      • 这是一个“省略”而不是“选择”:)
      【解决方案4】:

      可以解构的IIFE?:

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

      【讨论】:

        【解决方案5】:

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

        扩展您自己的答案 - 如果您要编写一个 extract 实用程序(我会自己动手)...您可以通过 currying 使其更灵活 - 允许您交换顺序参数(特别是将数据源放在最后),同时在接受属性名称时仍然是可变的。

        我认为这个签名: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))

        【讨论】:

          【解决方案6】:

          第一种方法优雅易读。

          请不要通过一些变通方法混淆简单的操作。其他需要维护此代码的人,包括未来的您自己,将来会非常感激。

          【讨论】:

            【解决方案7】:

            您可以尝试reduce 而非[x,y,z] 数组:

            let source = {
                x: 120,
                y: 200,
                z: 150,
                radius: 10,
                color: 'red',
            };
            
            const coords = ['x','y','z'].reduce((a,c) => Object.assign(a,{[c]: source[c]}), {});
            
            console.log(coords);
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2019-01-13
              • 2011-09-18
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多