map function for objects (instead of arrays)

前端 未结 30 1919
无人及你
无人及你 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:05

    Hey wrote a little mapper function that might help.

        function propertyMapper(object, src){
             for (var property in object) {   
               for (var sourceProp in src) {
                   if(property === sourceProp){
                     if(Object.prototype.toString.call( property ) === '[object Array]'){
                       propertyMapper(object[property], src[sourceProp]);
                       }else{
                       object[property] = src[sourceProp];
                    }
                  }
                }
             }
          }
    
    0 讨论(0)
  • 2020-11-22 05:06

    Minimal version (es6):

    Object.entries(obj).reduce((a, [k, v]) => (a[k] = v * v, a), {})
    
    0 讨论(0)
  • 2020-11-22 05:06

    For maximum performance.

    If your object doesn't change often but needs to be iterated on often I suggest using a native Map as a cache.

    // example object
    var obj = {a: 1, b: 2, c: 'something'};
    
    // caching map
    var objMap = new Map(Object.entries(obj));
    
    // fast iteration on Map object
    objMap.forEach((item, key) => {
      // do something with an item
      console.log(key, item);
    });

    Object.entries already works in Chrome, Edge, Firefox and beta Opera so it's a future-proof feature. It's from ES7 so polyfill it https://github.com/es-shims/Object.entries for IE where it doesn't work.

    0 讨论(0)
  • 2020-11-22 05:06

    I came upon this as a first-item in a Google search trying to learn to do this, and thought I would share for other folsk finding this recently the solution I found, which uses the npm package immutable.

    I think its interesting to share because immutable uses the OP's EXACT situation in their own documentation - the following is not my own code but pulled from the current immutable-js documentation:

    const { Seq } = require('immutable')
    const myObject = { a: 1, b: 2, c: 3 }
    Seq(myObject).map(x => x * x).toObject();
    // { a: 1, b: 4, c: 9 } 
    

    Not that Seq has other properties ("Seq describes a lazy operation, allowing them to efficiently chain use of all the higher-order collection methods (such as map and filter) by not creating intermediate collections") and that some other immutable-js data structures might also do the job quite efficiently.

    Anyone using this method will of course have to npm install immutable and might want to read the docs:

    https://facebook.github.io/immutable-js/

    0 讨论(0)
  • 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. :-)

    0 讨论(0)
  • 2020-11-22 05:10

    I handle only strings to reduce exemptions:

    Object.keys(params).map(k => typeof params[k] == "string" ? params[k] = params[k].trim() : null);
    
    0 讨论(0)
提交回复
热议问题