map function for objects (instead of arrays)

前端 未结 30 2417
无人及你
无人及你 2020-11-22 04:23

I have an object:

myObject = { \'a\': 1, \'b\': 2, \'c\': 3 }

I am looking for a native method, similar to Array.prototype.map

30条回答
  •  执笔经年
    2020-11-22 05:10

    How about a one liner with immediate variable assignment in plain JS (ES6 / ES2015) ?

    Making use of spread operator and computed key name syntax:

    let newObj = Object.assign({}, ...Object.keys(obj).map(k => ({[k]: obj[k] * obj[k]})));
    

    jsbin

    Another version using reduce:

    let newObj = Object.keys(obj).reduce((p, c) => ({...p, [c]: obj[c] * obj[c]}), {});
    

    jsbin

    First example as a function:

    const oMap = (o, f) => Object.assign({}, ...Object.keys(o).map(k => ({ [k]: f(o[k]) })));
    
    // To square each value you can call it like this:
    let mappedObj = oMap(myObj, (x) => x * x);
    

    jsbin

    If you want to map a nested object recursively in a functional style, it can be done like this:

    const sqrObjRecursive = obj =>
      Object.keys(obj).reduce(
        (newObj, key) =>
          obj[key] && typeof obj[key] === "object"
            ? { ...newObj, [key]: sqrObjRecursive(obj[key]) } // recurse.
            : { ...newObj, [key]: obj[key] * obj[key] }, // square val.
        {}
      );       
    

    jsbin

    Or more imperatively, like this:

    const sqrObjRecursive = obj => {
      Object.keys(obj).forEach(key => {
        if (typeof obj[key] === "object") obj[key] = sqrObjRecursive(obj[key]);
        else obj[key] = obj[key] * obj[key];
      });
      return obj;
    };
    

    jsbin

    Since ES7 / ES2016 you can use Object.entries() instead of Object.keys() e.g. like this:

    let newObj = Object.assign({}, ...Object.entries(obj).map(([k, v]) => ({[k]: v * v})));
    

    ES2019 introduced Object.fromEntries(), which simplifies this even more:

    let newObj = Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, v * v]));
    


    Inherited properties and the prototype chain:

    In some rare situation you may need to map a class-like object which holds properties of an inherited object on its prototype-chain. In such cases Object.keys() won't work, because Object.keys() does not enumerate inherited properties. If you need to map inherited properties, you should use for (key in myObj) {...}.

    Here is an example of an object which inherits the properties of another object and how Object.keys() doesn't work in such scenario.

    const obj1 = { 'a': 1, 'b': 2, 'c': 3}
    const obj2 = Object.create(obj1);  // One of multiple ways to inherit an object in JS.
    
    // Here you see how the properties of obj1 sit on the 'prototype' of obj2
    console.log(obj2)  // Prints: obj2.__proto__ = { 'a': 1, 'b': 2, 'c': 3}
    
    console.log(Object.keys(obj2));  // Prints: an empty Array.
    
    for (key in obj2) {
      console.log(key);              // Prints: 'a', 'b', 'c'
    }
    

    jsbin

    However, please do me a favor and avoid inheritance. :-)

提交回复
热议问题