# 字符串转路径数组
const charCodeOfDot = '.'.charCodeAt(0);
const reEscapeChar = /\\(\\)?/g;
const rePropName = RegExp(
// Match anything that isn't a dot or bracket.
'[^.[\\]]+' + '|' +
// Or match property names within brackets.
'\\[(?:' +
// Match a non-string expression.
'([^"\'][^[]*)' + '|' +
// Or match strings (supports escaping characters).
'(["\'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2' + ')\\]' + '|' +
// Or match "" as the space between consecutive dots or empty brackets.
'(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))'
, 'g');
const stringToPath = memoizeCapped(string => {
const result = [];
if (string.charCodeAt(0) === charCodeOfDot) {
result.push('');
}
string.replace(rePropName, (match, expression, quote, subString) => {
let key = match;
if (quote) {
key = subString.replace(reEscapeChar, '$1');
} else if (expression) {
key = expression.trim();
}
result.push(key);
});
return result;
});
这一段代码,主要是正则表达式比较复杂,其目的是想将a.b.c
字符串转换成['a', 'b', 'c']
这样的数组。
主要处理了以下几种情况
# 处理以.
开头的字符串
const charCodeOfDot = '.'.charCodeAt(0);
const result = [];
if (string.charCodeAt(0) === charCodeOfDot) {
result.push('');
}
以.
开头的字符串,lodash
会认为最外层的属性为空字符串。
相当于.a.b.c
转换为['', 'a', 'b', 'c']
。
# 处理常规路径
处理最常规的字符串,例如a.b.c
,可以简化成如下代码:
string.replace(rePropName, (match) => {
let key = match;
result.push(key);
});
match
为匹配成功的字符串,直接push
即可。
# 处理中括号取值
在数组取值的情况下,会存在中括号索引的情况,如a[0].b
这样的形式,转换为数组是['a', '0', 'b']
。
在这种情况,可以简化如下的形式:
string.replace(rePropName, (match, expression) => {
let key = match;
else if (expression) {
key = expression.trim();
}
result.push(key);
})
在匹配到索引0
时,match
的结果是[0]
,但是这里expression
的结果是0
,因此key
为0
。
# 处理带引号的情况
中括号的情况下,可能会存在有引号的情况,如a['0'].b
的形式,如果这个string
是通过接口返回的,可能还会带上转义字符,如a[\'0\'].b
,在这种情况下,quote
会存在值,
,这是subString
在没转义的情况下为0
,在有转义字符的情况下为\'0\'
,因此需要用reEscapeChar
正则将转义字符替换掉。