【问题标题】:Is it possible to make an object with keys matching another object, values matching function input arguments?是否可以使用与另一个对象匹配的键、与函数输入参数匹配的值来创建对象?
【发布时间】:2018-02-05 13:10:02
【问题描述】:

此处的想象代码和问题:

function makeCreator(obj) {
  return (...args) => {
    return {
      type: obj.type,
      ...obj.keys: ...args, 

      // the above is invalid js code, but I'd like 
      // the keys and values to be automatically paired
      ///////////////////////////////////////////////////////
      // Question: how to make it work using spread operator only?
      // I mean, is it possible to do everything with "just "the spread operator?
      ///////////////////////////////////////////////////////
    };
  }
}

示例输入

const obj1 = {
  type: 'something',
  key1: 10,
  key2: 20
};

示例输出

const generatedForObj = makeCreator(obj1);

// it should equivalents to
function generatedForObj(v1, v2) {
  return {
    type: 'something',
    key1: v1,
    key2: v2,
  };
}

// use it like this
const result = generatedForObj (100, 200); 
// result is { type: 'something', key1: 100, key2: 200 }

实际上我正在尝试实现某种 redux 的动作创建器,如果这些信息有帮助的话。

还提供(应该)工作版本,但我想尝试传播运算符:

function makeCreator(obj) {
  return (...args) => {
    let { type: obj.type, ...exceptType } = obj;

    Object.keys(exceptType).forEach((key, index) => { 
      exceptType[key] = args[index];
    });

    return {
      type: obj.type,
      ...exceptType,
    };
  }
}

【问题讨论】:

    标签: javascript ecmascript-6 spread-syntax


    【解决方案1】:

    可能,从 ES2015 开始,但这可能不是一个好主意。您可以使用Object.getOwnPropertyNames 以稳定的顺序获取对象的字符串命名属性。顺序稍微复杂,但在您的示例中,顺序将是typekey1key2,因为

    1. 所有这些都是字符串键控
    2. 它们都不匹配数组索引的定义(不,对象不是数组并不重要)
    3. 没有一个是继承的
    4. 这是创建属性的顺序

    同样,可能

    const makeCreator = obj => {
      const keys = Object.getOwnPropertyNames(obj).filter(key => key !== "type");
      return (...args) => {
        const result = {type: obj.type};
        keys.forEach((key, index) => {
          result[key] = args[index];
        });
        return result;
      }
    

    const obj1 = {
      type: 'something',
      key1: 10,
      key2: 20
    };
    
    const makeCreator = obj => {
      const keys = Object.getOwnPropertyNames(obj).filter(key => key !== "type");
      return (...args) => {
        const result = {type: obj.type};
        keys.forEach((key, index) => {
          result[key] = args[index];
        });
        return result;
      }
    };
    
    const generatedForObj = makeCreator(obj1);
    
    // use it like this
    const result = generatedForObj (100, 200); 
    console.log(result);

    但是,属性顺序从 ES2015+ 开始是新的,这意味着旧的 JavaScript 引擎(必然)不支持它,并且它不能被 polyfill。最好明确地为您的makeCreator 提供一组属性名称:

    const makeCreator = (obj, keys) => {
      return (...args) => {
        const result = {type: obj.type};
        keys.forEach((key, index) => {
          result[key] = args[index];
        });
        return result;
      }
    };
    

    用法:

    const generatedForObj = makeCreator(obj1, ["key1", "key2"]);
    

    const obj1 = {
      type: 'something',
      key1: 10,
      key2: 20
    };
    
    const makeCreator = (obj, keys) => {
      return (...args) => {
        const result = {type: obj.type};
        keys.forEach((key, index) => {
          result[key] = args[index];
        });
        return result;
      }
    };
    
    const generatedForObj = makeCreator(obj1, ["key1", "key2"]);
    
    // use it like this
    const result = generatedForObj (100, 200); 
    console.log(result);

    你的评论:

    我想知道是否有可能使这项工作“仅使用”扩展运算符?就像我在想象部分演示的那样?

    不,扩展符号(它不是运算符)现在只能扩展数组条目;在 ES2018(或现在通过转译器)中,它将能够传播对象属性及其值(因为该提案处于第 3 阶段,并且可能会及时推进到 2018 年的规范中),但名称和值来自同一个对象。它不能从两个来源(一个地方的名称,另一个地方的值)中提取。

    【讨论】:

    • 您好,感谢您的回复!我想我的问题不清楚,我想知道是否有可能使这项工作“仅使用”传播运算符?就像我在想象部分演示的那样?
    • @MarsonMao:不;我已添加到问题的末尾。
    • 好的,由于没有其他答案,而且我的评论也已得到答复,我将其标记为已接受。
    猜你喜欢
    • 1970-01-01
    • 2019-10-25
    • 1970-01-01
    • 2021-02-07
    • 1970-01-01
    • 2019-06-30
    • 2022-09-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多