Object.get这个方法,我觉得是在工作中比较常用的。而且ES6没有原生实现的。在之前的文章中。尝试用Reduce实现了一个类似的方法。可以在JS数组那篇文章中的末尾找到。我们来看一看Lodash是怎么实现的。
我们先来看看他的用法。这个函数的主要作用是,根据对象的路径获取值。1
2
3
4
5
6
7
8
9
10const 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'
我们可以看出来,路径可以是一个字符串,可以是一个数组。我们最后还可以给一个默认值,当根据这路径没有找到对应值得时候,而返回默认值。
下面我们来看一下源码:1
2
3
4
5
6function get(object, path, defaultValue) {
const result = object == null ? undefined : baseGet(object, path)
return result === undefined ? defaultValue : result
}
export default
我们可以看到如果传入的对象为undefined或者根据路径查找出的结果为undefined的时候,就返回defaultValue。否则返回查找的结果。主要的逻辑还是在baseGet中。
1 | import castPath from './castPath.js' |
在baseGet中引入了两个方法。首先是这个castPath
这个方法是强制转换为path数组。可以先看一下它的实现。1
2
3
4
5
6function castPath(value, object) {
if (Array.isArray(value)) {
return value
}
return isKey(value, object) ? [value] : stringToPath(value)
}
如果本身就是一个path数组,就返回value。如果不是的话,就调用isKey
这个方法isKey
这个方法主要是用来检测value是否是属性名,而不是属性路径。我们先不看里面的具体实现。就看最后的return,如果这个value是对象的名的话(也就是传入的这个value不带.或者[])我们就直接返回这个数组只包含value这一个值。否则返回通过stringToPath这个函数,返回的路径数组。
我们回到前面一个函数,我们看下面while部分的内容。1
2
3while (object != null && index < length) {
object = object[toKey(path[index++])]
}
如果object不为空,我们就一直取数组里面的值,然后通过数组里面的key找到对应的value。起初刚看这个时候,还在想直接用object=
是不是修改传入的对象。后面才发现真的是基础不牢。其实在JavaScript函数的参数都是值传递,而传入对象也只是传入对象地址的值。我们在用object进行赋值的时候。实际是切断了与传入地址之间的关系。所以并不会改变原对象。这部分之后会单独开一篇文章进行讲解。剩下的核心就是toKey这个方法。
这个方法也很简单1
2
3
4
5
6
7
8
9const INFINITY = 1 / 0;
function toKey(value) {
if (typeof value === 'string' || isSymbol(value)) {
return value
}
const result = `${value}`
return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result
}
这个方法就是讲不是string和Symbol的key转为string。不得不佩服这种开源库想的真周到。
我们可以看到其中有一个非常冷面的知识点。
就是当你给一个变量赋值为+0或者0的时候,它都为0。而赋值为-0的时候它等于-0;1
2
3const a = 0; //console -> 0
const b = +0; //console -> 0
const c = -0; //console -> 0
而经过字符串转换的时候,0、+0、-0都会转换为0。Lodash居然考虑到了这一点,他用 1/value 是否等于 -(1/0)来判断传入的这个value是否为-0。从而修复了这一个问题。
又扯远了。我们回去继续看。其实核心代码很简单,就是一个不断根据key取值的一个过程。但是通过源码的学习。我们能学习到很多冷门的知识点和一些边界检测。这个过程也是十分有意思的。