JS 将字符串路径path 转化为类似于Swift的键路径

41 min read
/**
 * 将例如像 a.b.c 或 a[1].b 的字符串转换为路径数组
 *
 * @param string 要转换的字符串
 */
export const keyToPath = (string: string) => {
  const result = [];

  if (string.charCodeAt(0) === '.'.charCodeAt(0)) {
    result.push('');
  }

  string.replace(
    new RegExp(
      '[^.[\\]]+|\\[(?:([^"\'][^[]*)|(["\'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2)\\]|(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))',
      'g'
    ),
    (match, expression, quote, subString) => {
      let key = match;
      if (quote) {
        key = subString.replace(/\\(\\)?/g, '$1');
      } else if (expression) {
        key = expression.trim();
      }
      result.push(key);
      return '';
    }
  );

  return result;
};

这段代码的作用是将一个复杂的对象属性路径字符串,例如 'a.b.c''a[1].b',转换为一个属性路径数组,例如 ['a', 'b', 'c']['a', '1', 'b']。这个函数对于操作复杂嵌套的 JavaScript 对象非常有用。

以下是一个具体的使用示范:

const objectPath1 = 'a.b.c';
const pathArray1 = keyToPath(objectPath1);
console.log(pathArray1); // ['a', 'b', 'c']

const objectPath2 = 'a[1].b';
const pathArray2 = keyToPath(objectPath2);
console.log(pathArray2); // ['a', '1', 'b']

const objectPath3 = 'users[0].name.first';
const pathArray3 = keyToPath(objectPath3);
console.log(pathArray3); // ['users', '0', 'name', 'first']

这样得到的属性路径数组,可以用于访问或者修改复杂嵌套的 JavaScript 对象。例如,你可以使用 Lodash 的 _.get()_.set() 方法:

import _ from 'lodash';

const data = {
  users: [
    { name: { first: 'John', last: 'Doe' } },
    { name: { first: 'Jane', last: 'Doe' } },
  ],
};

const path = 'users[0].name.first';
const pathArray = keyToPath(path);

// get value
const value = _.get(data, pathArray);
console.log(value); // 'John'

// set value
_.set(data, pathArray, 'Jack');
console.log(data.users[0].name.first); // 'Jack'

这是一个非常常见的模式,用于处理 JavaScript 中的深度嵌套对象。