JS - deep map function

后端 未结 8 457
挽巷
挽巷 2020-12-06 04:48

Underscore.js has a very useful map function.

_.map([1, 2, 3], function(num){ return num * 3; });
=> [3, 6, 9]
_.map({one: 1, two: 2, three: 3         


        
相关标签:
8条回答
  • 2020-12-06 05:27

    Based on @megawac response, I made some improvements.

    function mapExploreDeep(object, iterateeReplace, iterateeExplore = () => true) {
        return _.transform(object, (acc, value, key) => {
            const replaced = iterateeReplace(value, key, object);
            const explore = iterateeExplore(value, key, object);
            if (explore !== false && replaced !== null && typeof replaced === 'object') {
                acc[key] = mapExploreDeep(replaced, iterateeReplace, iterateeExplore);
            } else {
                acc[key] = replaced;
            }
            return acc;
        });
    }
    
    _.mixin({
        mapExploreDeep: mapExploreDeep;
    });
    

    This version allows you to replace even objects & array themselves, and specify if you want to explore each objects/arrays encountered using the iterateeExplore parameter.

    See this fiddle for a demo

    0 讨论(0)
  • 2020-12-06 05:38

    I've published a package called Deep Map to address this very need. And in case you want to map an object's keys rather than its values, I've written Deep Map Keys.

    Notably, none of the answers on here address a significant problem: circular references. Here is a somewhat naive implementation that deals with these rotters:

    function deepMap(value, mapFn, thisArg, key, cache=new Map()) {
      // Use cached value, if present:
      if (cache.has(value)) {
        return cache.get(value);
      }
    
      // If value is an array:
      if (Array.isArray(value)) {
        let result = [];
        cache.set(value, result); // Cache to avoid circular references
    
        for (let i = 0; i < value.length; i++) {
          result.push(deepMap(value[i], mapFn, thisArg, i, cache));
        }
        return result;
    
      // If value is a non-array object:
      } else if (value != null && /object|function/.test(typeof value)) {
        let result = {};
        cache.set(value, result); // Cache to avoid circular references
    
        for (let key of Object.keys(value)) {
          result[key] = deepMap(value[key], mapFn, thisArg, key, cache);
        }
        return result;
    
      // If value is a primitive:
      } else {
        return mapFn.call(thisArg, value, key);
      }
    }
    

    And you can use it like this:

    class Circlular {
      constructor() {
        this.one = 'one';
        this.arr = ['two', 'three'];
        this.self = this;
      }
    }
    
    let mapped = deepMap(new Circlular(), str => str.toUpperCase());
    
    console.log(mapped.self.self.self.arr[1]); // 'THREE'
    

    Of course, the example above is in ES2015. See Deep Map for a more optimized – though less terse – ES5-compatible implementation written in TypeScript.

    0 讨论(0)
提交回复
热议问题