get这个方法,在lodash中是出场率很高的方法,初识起来有些疑惑,看了demo,又很直观。
下边是它的使用说明
Gets the value at `path` of `object`. If the resolved value is
`undefined`, the `defaultValue` is returned in its place.
根据object对象的path路径获取值。如果解析值是undefined,就返回一个默认的值(defaultValue)
* var object = { 'a': [{ 'b': { 'c': 3 } }] };
*
* _.get(object, 'a[0].b.c');
* // => 3
*
* _.get(object, ['a', '0', 'b', 'c']);
* // => 3
*
* _.get(object, 'a.b.c', 'default');
* // => 'default'
暂时不考虑第第三个参数,只考虑第二个参数,该参数的含义就是路径。 指向object的路径。
这个get方法事实上等同于我们取object上的某个属性的值。object['a'][0]['b']['c']
或者 object.a[0].b.c
.
如果把复杂对象当成一个树来看,['a'][0]['b']['c']
抑或是a[0].b.c
都是树上的一个个树枝,树枝的终端可以另一个树枝,或者是一个具体的果实
.
那该如何实现一个get方法呢。首先,第一个参数是具体的对象,第二个参数是一个路径,该路径我们当然会有一个约定俗成的格式,既足够直观理解,又便于我们格式化处理。
当然还要避免错误处理,返回相应的默认值。
lodash的实现如下
function get(object, path, defaultValue) {
var result = object == null ? undefined : baseGet(object, path);
return result === undefined ? defaultValue : result;
}
export default get;
这里引入了一个baseGet。 get => baseGet
import castPath from './_castPath.js';
import toKey from './_toKey.js';
function baseGet(object, path) {
path = castPath(path, object);
var index = 0,
length = path.length;
while (object != null && index < length) {
object = object[toKey(path[index++])];
}
return (index && index == length) ? object : undefined;
}
我们先不去看castPath的方法,就能很轻易的判断它返回的应该是一个路径相关的数组。
比如
// -var object = { 'a': [{ 'b': { 'c': 3 } }] };
['a', '0', 'b', 'c']
//
随着while遍历,object都会被重新赋值。最终取到我们目标的指
return (index && index == length) ? object : undefined;
确认path中有确定想取的值。否则就是取不到值,undefined。
接下来我们可以考虑下castPath到底做了什么了。
/**
* Casts `value` to a path array if it's not one.
* value如果不是数组,就将它转换成一个路径 数组。
* @private
* @param {*} value The value to inspect. 被检查的值
* @param {Object} [object] The object to query keys on. 被查询对象是否有对应的key。
* @returns {Array} Returns the cast property path array. 返回被转换的路径数组
*/
function castPath(value, object) {
if (isArray(value)) {
return value;
}
return isKey(value, object) ? [value] : stringToPath(toString(value));
}
isKey(value, object) 应该是用来判断value是object的key,如果是,那二话不说直接返回了。
换做是我,我要如何写这个isKey,可能我不会单独写一个方法。
粗心点,我可能直接就写object[value]来判断了。
isKey
比我们想的多的多。看看它是怎么写的
/** Used to match property names within property paths. */
var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,
reIsPlainProp = /^\w*$/;
//reIsDeepProp 用来匹配属性名里包含路径属性 例如什么. [] \这种
/**
* Checks if `value` is a property name and not a property path.
* 检查value是一个属性名,不是属性路径
* @private
* @param {*} value The value to check. 被检查的值
* @param {Object} [object] The object to query keys on.
* @returns {boolean} Returns `true` if `value` is a property name, else `false`.
*/
function isKey(value, object) {
if (isArray(value)) { // 数组,直接返回false
return false;
}
var type = typeof value; // 对应的集中类型直接返回true,看到没,没有字符串,没有字符串。如果你考虑到
if (type == 'number' || type == 'symbol' || type == 'boolean' ||
value == null || isSymbol(value)) {
return true;
}
return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||
(object != null && value in Object(object));
}
return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||
(object != null && value in Object(object));
先判断是字符串,而且不是那种包含.[]
。
value in Object(object))
判断value是Object的key,返回一个bol
还剩下一个stringToPath
stringToPath(toString(value));
很显然,它的作用是将类似于"a[0]b.c"
规则的字符串转换成数组路径["a", "0", "b", "c"]
var stringToPath = memoizeCapped(function(string) {
var result = [];
if (string.charCodeAt(0) === 46 /* . */) {
result.push('');
}
//主要是下边这两行
string.replace(rePropName, function(match, number, quote, subString) {
result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match));
});
return result;
});
正则表达式的知识在自己补充吧。简单说就是匹配出我需要的 a,0,b,c.
至于memoize下一篇再说吧。