moleculerjs / moleculer

:rocket: Progressive microservices framework for Node.js
https://moleculer.services/
MIT License
6.14k stars 582 forks source link

[lodash] Remove usage of _.get #753

Open abdavid opened 4 years ago

abdavid commented 4 years ago

See #433 for context.

Describe the solution you'd like Remove usage of _.get throughout Moleculer.

Describe alternatives you've considered Source: https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore#_get

// Native
const get = (obj, path, defaultValue = undefined) => {
  const travel = regexp =>
    String.prototype.split
      .call(path, regexp)
      .filter(Boolean)
      .reduce((res, key) => (res !== null && res !== undefined ? res[key] : res), obj);
  const result = travel(/[,[\]]+?/) || travel(/[,[\].]+?/);
  return result === undefined || result === obj ? defaultValue : result;
};

Another suggestion could be https://github.com/hughfdjackson/delve though I would maybe recommend adopting the code since the lib has not been updated for the last five years, and it from jsPerf tests I could find still outperforms _.get (https://jsperf.com/lodash-get-vs-monster-method/5)

// isObject would be reused from _.isObject replacement
const isObject = v => {
    return v !== null && typeof v === 'object'
};

const unpackOne = (o, path) => {
    if (o == null)
        return undefined;
    else
        return o[path];
};

const delve = (o, path) => {
    const parts = path.split('.');
    let result = o;
    let part;

    while (parts.length) {
        part = parts.shift();
        result = unpackOne(result, part)
    }

    return result;
};

delve.has = (o, path) => {
    if (delve(o, path) !== undefined)
        return true;

    const parts = path.split('.');
    const unpacked = delve(o, parts.slice(0, -1).join('.'));
    const last = parts.slice(-1);

    if (isObject(unpacked))
        return last in unpacked;
    else
        return false;
};

// usage

const obj = {
      first: {
        second: {
          third: 'property'
        }
      }
    }
const result = delve(obj, 'first.second.third');
// 'property'

Additional context https://github.com/moleculerjs/moleculer/search?q=_.get&unscoped_q=_.get

al66 commented 4 years ago

What's about this:

function getValue(obj, path, defaultValue = undefined) {
    if (!path || typeof path !== "string" ) return null;
    let i;
    path = path.split(".");
    for (i = 0; i < path.length; i++) {
        if (!obj[path[i]]) {obj = null; break;}
        obj = obj[path[i]];
    }
    return obj || defaultValue;
}

Benchmark result:

propsoal x 4,046,174 ops/sec ±0.76% (90 runs sampled)
native x 1,466,649 ops/sec ±0.54% (92 runs sampled)
Fastest is propsoal