We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
本文为读 lodash 源码的第一百一十九篇,后续文章会更新到这个仓库中,欢迎 star:pocket-lodash
gitbook也会同步仓库的更新,gitbook地址:pocket-lodash
import assignValue from './assignValue.js' import castPath from './castPath.js' import isIndex from './isIndex.js' import isObject from '../isObject.js' import toKey from './toKey.js'
《lodash源码分析之assignValue》 《lodash源码分析之castPath》 《lodash源码分析之isIndex》 《lodash源码分析之isObject》 《lodash源码分析之toKey》
baseSet 接入一个 object ,然后将值 value 设置到属性路径 key 上。
baseSet
object
value
key
源码如下:
function baseSet(object, path, value, customizer) { if (!isObject(object)) { return object } path = castPath(path, object) const length = path.length const lastIndex = length - 1 let index = -1 let nested = object while (nested != null && ++index < length) { const key = toKey(path[index]) let newValue = value if (index != lastIndex) { const objValue = nested[key] newValue = customizer ? customizer(objValue, key, nested) : undefined if (newValue === undefined) { newValue = isObject(objValue) ? objValue : (isIndex(path[index + 1]) ? [] : {}) } } assignValue(nested, key, newValue) nested = nested[key] } return object }
if (!isObject(object)) { return object }
object 参数要通过 isObject 的检测,可以是数组、对象和函数等。
isObject
如果通不过检测,不需要再走后续的步骤,因为其他类型没办法往上面设置属性。
path = castPath(path, object) const length = path.length const lastIndex = length - 1 let index = -1 let nested = object
使用 castPath 将 path 转换成路径数组。
castPath
path
用 length 保存路径数组 path 的长度,方便后续遍历的终止条件判断。
length
使用 lastIndex 保存路径数组最后一个路径的索引,这个变量的作用后面再说。
lastIndex
使用 index 来保存当前遍历到的属性的索引值,也作为遍历指示器。
index
使用 nested 保存当前路径层级的值。
nested
假设传入了这样的对象:
const object = { a: { b: { c: 1 } } }
要将路径 a.b.c 的值设置为 2。
a.b.c
2
在这种情况下,不需要考虑异常情况,使用源码中的以下代码即可实现:
while (++index < length) { const key = toKey(path[index]) let newValue = value if (index != lastIndex) { const objValue = nested[key] newValue = objValue } assignValue(nested, key, newValue) nested = nested[key] }
在遍历 path 的过程中,判断当前的索引 index 是不是最后的属性,如果不是,则使用 nexted[key] 将当前层级的值取出来。例如在第一层 a 处,取得的值为 b:{c: 1} 。然后使得 assignValue 将值重新设置回去,其实在最后一层属性之前,原对象一点变化都没有,就是将当层的值取出,再设置回去。
nexted[key]
a
b:{c: 1}
assignValue
但是在最后一层时,newValue 的值为传入的 value ,也就实现了指定路径的值的更新。
newValue
同样是 a.b.c 的路径,但是传入的对象如下:
const object = {}
这时,取第一层 a 时,取得的值为 undefined ,也即当前的 nexted 值为 undefined ,此时使用 assignValue 来赋值到 undefined 上,肯定与结果不符。
undefined
nexted
这时,就需要对每一层都要进行一个判断,如果当前值不能通过 isObject 检测,也即没办法往上面设置属性,就需要帮它生成一个空的对象或者数组,以便后续的层级能在上面设置属性。
代码修改如下:
while (++index < length) { const key = toKey(path[index]) let newValue = value if (index != lastIndex) { const objValue = nested[key] newValue = isObject(objValue) ? objValue : (isIndex(path[index + 1]) ? [] : {}) } assignValue(nested, key, newValue) nested = nested[key] }
使用 isIndex 来判断是不是数组的索引类型,如果是,则使用空数组,否则使用空对象。
isIndex
customizer
baseSet 作为内部方法,支持传入 customizer 来返回下一个值,不一定是 isObject 这样的判断。
如果有传 customizer ,则 newValue 直接使得 customizer 的值。
if (index != lastIndex) { const objValue = nested[key] newValue = customizer ? customizer(objValue, key, nested) : undefined if (newValue === undefined) { newValue = isObject(objValue) ? objValue : (isIndex(path[index + 1]) ? [] : {}) } }
如果 newValue 为 undefined ,则还是走 isObject 的判断。
署名-非商业性使用-禁止演绎 4.0 国际 (CC BY-NC-ND 4.0)
最后,所有文章都会同步发送到微信公众号上,欢迎关注,欢迎提意见:
作者:对角另一面
The text was updated successfully, but these errors were encountered:
No branches or pull requests
本文为读 lodash 源码的第一百一十九篇,后续文章会更新到这个仓库中,欢迎 star:pocket-lodash
gitbook也会同步仓库的更新,gitbook地址:pocket-lodash
依赖
《lodash源码分析之assignValue》
《lodash源码分析之castPath》
《lodash源码分析之isIndex》
《lodash源码分析之isObject》
《lodash源码分析之toKey》
源码分析
baseSet
接入一个object
,然后将值value
设置到属性路径key
上。源码如下:
处理
object
不是对象类型的情况object
参数要通过isObject
的检测,可以是数组、对象和函数等。如果通不过检测,不需要再走后续的步骤,因为其他类型没办法往上面设置属性。
路径转换和几个变量
使用
castPath
将path
转换成路径数组。用
length
保存路径数组path
的长度,方便后续遍历的终止条件判断。使用
lastIndex
保存路径数组最后一个路径的索引,这个变量的作用后面再说。使用
index
来保存当前遍历到的属性的索引值,也作为遍历指示器。使用
nested
保存当前路径层级的值。遍历及设置值
假设传入了这样的对象:
要将路径
a.b.c
的值设置为2
。在这种情况下,不需要考虑异常情况,使用源码中的以下代码即可实现:
在遍历
path
的过程中,判断当前的索引index
是不是最后的属性,如果不是,则使用nexted[key]
将当前层级的值取出来。例如在第一层a
处,取得的值为b:{c: 1}
。然后使得assignValue
将值重新设置回去,其实在最后一层属性之前,原对象一点变化都没有,就是将当层的值取出,再设置回去。但是在最后一层时,
newValue
的值为传入的value
,也就实现了指定路径的值的更新。处理异常情况
同样是
a.b.c
的路径,但是传入的对象如下:这时,取第一层
a
时,取得的值为undefined
,也即当前的nexted
值为undefined
,此时使用assignValue
来赋值到undefined
上,肯定与结果不符。这时,就需要对每一层都要进行一个判断,如果当前值不能通过
isObject
检测,也即没办法往上面设置属性,就需要帮它生成一个空的对象或者数组,以便后续的层级能在上面设置属性。代码修改如下:
使用
isIndex
来判断是不是数组的索引类型,如果是,则使用空数组,否则使用空对象。customizer
支持baseSet
作为内部方法,支持传入customizer
来返回下一个值,不一定是isObject
这样的判断。如果有传
customizer
,则newValue
直接使得customizer
的值。如果
newValue
为undefined
,则还是走isObject
的判断。License
署名-非商业性使用-禁止演绎 4.0 国际 (CC BY-NC-ND 4.0)
最后,所有文章都会同步发送到微信公众号上,欢迎关注,欢迎提意见:
作者:对角另一面
The text was updated successfully, but these errors were encountered: