lodash的get方法
参数
- object (Object): 要检索的对象。
- path (Array|string): 要获取属性的路径。
- [defaultValue] (*): 如果解析值是 undefined ,这值会被返回。
例子
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'
get
- 判断了对象为null返回undefined
- baseGet,实际实现也在baseGet中
- 第三个参数default 即result为undefined时默认值
function get(object, path, defaultValue) {
const result = object == null ? undefined : baseGet(object, path)
return result === undefined ? defaultValue : result
}
baseGet
- cashPath 实际上就是把字符串转成数组,如果传入的就是数组就直接返回
- tokey 对string类型和Symbol类型的key和数字类型做一层处理
- 通过while读取传入的path==>object下的参数
function baseGet(object, path) {
path = castPath(path, object)
let index = 0
const length = path.length
while (object != null && index < length) {
object = object[toKey(path[index++])]
}
return (index && index == length) ? object : undefined
}
cashPath
- isKey 判断path是不是当前对象的key
- stringToPath 如果传入的path不是当前对象的key,就调用该方法把字符串转成对应的数组
function castPath(value, object) {
if (Array.isArray(value)) {
return value
}
return isKey(value, object) ? [value] : stringToPath(value)
}
isKey
- reIsDeepProp 这个正则匹配 'a[0].b.c' 这类字符串 (ps: 正则我看着就懵)
- value in Object(object) 就是遍历value在不在当前对象内
- isSymbol 判断当前对象是不是symbol类型 Object.prototype.toString.call
const reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/
const reIsPlainProp = /^\w*$/
/**
* Checks if `value` is a property name and not a property path.
*
* @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 (Array.isArray(value)) {
return false
}
const type = typeof value
if (type === 'number' || type === 'boolean' || value == null || isSymbol(value)) {
return true
}
return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||
(object != null && value in Object(object))
}
stringToPath
- memoizeCapped 用来做缓存的
- 通过rePropName正则replace操作 (ps: 这个正则我真有点懵)
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')
/**
* Converts `string` to a property path array.
*
* @private
* @param {string} string The string to convert.
* @returns {Array} Returns the property path array.
*/
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
})
memoizeCapped
- memoize传入func 和 缓存大小限制回调
- MAX_MEMOIZE_SIZE 最大限制缓存500条
const MAX_MEMOIZE_SIZE = 500
/**
* A specialized version of `memoize` which clears the memoized function's
* cache when it exceeds `MAX_MEMOIZE_SIZE`.
*
* @private
* @param {Function} func The function to have its output memoized.
* @returns {Function} Returns the new memoized function.
*/
function memoizeCapped(func) {
const result = memoize(func, (key) => {
const { cache } = result
if (cache.size === MAX_MEMOIZE_SIZE) {
cache.clear()
}
return key
})
return result
memoize
- 通过Map缓存func,如果存在当前key就直接读缓存
function memoize(func, resolver) {
if (typeof func !== 'function' || (resolver != null && typeof resolver !== 'function')) {
throw new TypeError('Expected a function')
}
const memoized = function(...args) {
const key = resolver ? resolver.apply(this, args) : args[0]
const cache = memoized.cache
if (cache.has(key)) {
return cache.get(key)
}
const result = func.apply(this, args)
memoized.cache = cache.set(key, result) || cache
return result
}
memoized.cache = new (memoize.Cache || Map)
return memoized
}
memoize.Cache = Map