fe-learning icon indicating copy to clipboard operation
fe-learning copied to clipboard

实现Lodash函数系列(一):_.get

Open metroluffy opened this issue 4 years ago • 2 comments

实现Lodash函数系列(一):_.get

题目

/**
 * object (Object): 要检索的对象。
 * path (string): 要获取属性的路径。
 * [defaultValue] (*): 如果解析值是 undefined ,这值会被返回。
 */
function _get(object, path, default) {

}

实现类似 lodashget 函数,根据 object对象的path路径获取值。 如果解析 value 是 undefined 会以 defaultValue 取代。

示例:

const object = { 'a': [{ 'b': { 'c': 3 } }] };

_get(object, 'a[0].b.c');
// => 3

_get(object, 'a.b.c', 'default');
// => 'default'

实现

function _get (source, path, defaultValue = undefined) {
  // 将数组格式的路径转化成dot格式的,再拆分成key数组
  // a[0].b -> a.0.b -> ['a', '0', 'b']
  const paths = path.replace(/\[(\d+)\]/g, '.$1').split('.')
  let result = source
  for (const p of paths) {
    result = Object(result)[p] // null 与 undefined 取属性会报错, 用Object包装一下
    // if (result === undefined) {
    //    return defaultValue
    // }
  }
  return result || defaultValue
}

参考文档

  1. 如何实现类似 lodash 的 get

metroluffy avatar May 07 '20 07:05 metroluffy

这个有个问题,如何 result === false,那不就返回 defaultValue 了吗

jsspace avatar Mar 31 '21 06:03 jsspace

my code

function _get (source, path, defaultValue = undefined) {
  // translate array case to dot case, then split witth .
  // a[0].b -> a.0.b -> ['a', '0', 'b']
  const keyList = path.replace(/\[(\d+)\]/g, '.$1').split('.')
 
  const result = keyList.reduce((obj, key) => {
      return Object(obj)[key]; // null undefined get attribute will throwError, Object() can return a object 
  }, source)
  return result === undefined ? defaultValue : result;
}

jsspace avatar Mar 31 '21 06:03 jsspace

handle path has a[0]["b"]["c"] testcase. It's built based on above @jsspace code.

function get (source, path, defaultValue = undefined) {
  // translate array case to dot case, then split witth .
  // a[0].b -> a.0.b -> ['a', '0', 'b']
  // a[0]["b"]["c"] -> a.0."b"."c" -> ['a', '0', '"b"', '"c"']
  const keyList = path.replace(/\[((\d+)|\"[a-zA-Z]+\")\]/g, '.$1').split('.')
 
  const result = keyList.reduce((obj, key) => {
      if (key.includes('"')) {
        const refinedKey = key.replace(/\"/g, '') // remove all double-quote characters within a key, so '"b"' -> 'b'
        return Object(obj)[refinedKey]
      }
      return Object(obj)[key]; // null undefined get attribute will throwError, Object() can return a object 
  }, source)
  return result === undefined ? defaultValue : result;
}

yhunglee avatar Jan 05 '25 07:01 yhunglee