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
baseDifference 可以用来获取指定数组与另一个数组的差集。
baseDifference
这个函数是内部函数,是后面实现其它比较函数的核心函数。
baseDifference 的方法签名如下:
baseDifference(array, values, iteratee, comparator)
第一和第二个参数是需要比较的两个数组;iteratee 可以返回一值映射值,比较时,可以使用映射的值来进行比较; comparator 是自定义比较函数,如果有传递,则调用自定义的比较函数来进行交集的比较。
iteratee
comparator
import SetCache from './SetCache.js' import arrayIncludes from './arrayIncludes.js' import arrayIncludesWith from './arrayIncludesWith.js' import map from '../map.js' import cacheHas from './cacheHas.js'
lodash源码分析之缓存使用方式的进一步封装
lodash源码分析之arrayIncludes
lodash源码分析之arrayIncludesWith
lodash源码分析之map的实现
lodash源码分析之cacheHas
const LARGE_ARRAY_SIZE = 200 function baseDifference(array, values, iteratee, comparator) { let includes = arrayIncludes let isCommon = true const result = [] const valuesLength = values.length if (!array.length) { return result } if (iteratee) { values = map(values, (value) => iteratee(value)) } if (comparator) { includes = arrayIncludesWith isCommon = false } else if (values.length >= LARGE_ARRAY_SIZE) { includes = cacheHas isCommon = false values = new SetCache(values) } outer: for (let value of array) { const computed = iteratee == null ? value : iteratee(value) value = (comparator || value !== 0) ? value : 0 if (isCommon && computed === computed) { let valuesIndex = valuesLength while (valuesIndex--) { if (values[valuesIndex] === computed) { continue outer } } result.push(value) } else if (!includes(values, computed, comparator)) { result.push(value) } } return result }
if (iteratee) { values = map(values, (value) => iteratee(value)) }
如果有传递 iteratee ,则先调用 map ,使用 iteratee 生成要比较数组的映射数组 values。
map
values
因为后面会有嵌套循环,避免重复调用 iteratee ,影响性能,所以一开始就需要生成 values 的映射数组。
这里使用了 isCommon 来标志是否使用普通方式来处理。
isCommon
if (comparator) { includes = arrayIncludesWith isCommon = false }
如果有传递比较函数,则将 isCommon 标记为 false,表示不用普通的方式来处理,后面可以看到,最后会使用 includes 方法来处理,也即 arrayIncludesWith 方法。
false
includes
arrayIncludesWith
else if (values.length >= LARGE_ARRAY_SIZE) { includes = cacheHas isCommon = false values = new SetCache(values) }
如果不需要使用自定义的比较方式,并且数组较大时(这里限定了200),则使用 SetCache 类来缓存数组。
SetCache
SetChche 其实使用的是 Map/Set 或者对象的方式来存储,避免大数组嵌套循环时造成的性能损耗。
SetChche
Map/Set
接下来就遍历第一个数组 array,将数组中的每一项和第二个数组的每一项比较。
array
if (isCommon && computed === computed) { let valuesIndex = valuesLength while (valuesIndex--) { if (values[valuesIndex] === computed) { continue outer } } result.push(value) } else if (!includes(values, computed, comparator)) { result.push(value) }
可以看到,如果 isCommon 没有标记为 false, 或者需要比较的值 computed 不为 NaN 时,都采用嵌套循环的方式来比较。循环完毕,没有在第二个数组中发现相同的项时,将该项存入数组 result 中。
computed
NaN
result
如果 isCommon 为 false 或者需要比较的值为 NaN 时,则调用 includes 方法来比较。
由之前的分析得知:
200
cacheHas
arrayIncludes
在看代码的时候,有一段十分奇怪:
value = (comparator || value !== 0) ? value : 0
这段代码的意思是,在没有提供 comparator 的情况下,如果 value === 0 ,则将 value 赋值为 0 。
value === 0
value
0
value === 0 时,可能为 +0 、-0 和 0 ,lodash 为什么要将它们都转为 0 呢?
+0
-0
后来看到 lodash 作者在 issue 中说,因为比较会用到 Set ,而 Set 是不能区分 +0 和 -0 的。
Set
Lodash系列——difference函数源码解析
value = (comparator || value !== 0) ? value : 0; does it work?
署名-非商业性使用-禁止演绎 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
作用与用法
baseDifference
可以用来获取指定数组与另一个数组的差集。这个函数是内部函数,是后面实现其它比较函数的核心函数。
baseDifference
的方法签名如下:第一和第二个参数是需要比较的两个数组;
iteratee
可以返回一值映射值,比较时,可以使用映射的值来进行比较;comparator
是自定义比较函数,如果有传递,则调用自定义的比较函数来进行交集的比较。依赖
lodash源码分析之缓存使用方式的进一步封装
lodash源码分析之arrayIncludes
lodash源码分析之arrayIncludesWith
lodash源码分析之map的实现
lodash源码分析之cacheHas
源码分析
iteratee的调用
如果有传递
iteratee
,则先调用map
,使用iteratee
生成要比较数组的映射数组values
。因为后面会有嵌套循环,避免重复调用
iteratee
,影响性能,所以一开始就需要生成values
的映射数组。性能优化
这里使用了
isCommon
来标志是否使用普通方式来处理。如果有传递比较函数,则将
isCommon
标记为false
,表示不用普通的方式来处理,后面可以看到,最后会使用includes
方法来处理,也即arrayIncludesWith
方法。如果不需要使用自定义的比较方式,并且数组较大时(这里限定了200),则使用
SetCache
类来缓存数组。SetChche
其实使用的是Map/Set
或者对象的方式来存储,避免大数组嵌套循环时造成的性能损耗。循环比较
接下来就遍历第一个数组
array
,将数组中的每一项和第二个数组的每一项比较。可以看到,如果
isCommon
没有标记为false
, 或者需要比较的值computed
不为NaN
时,都采用嵌套循环的方式来比较。循环完毕,没有在第二个数组中发现相同的项时,将该项存入数组result
中。如果
isCommon
为false
或者需要比较的值为NaN
时,则调用includes
方法来比较。由之前的分析得知:
comparator
,则includes
为arrayIncludesWith
values
的长度超过200
,则includes
为cacheHas
includes
为arrayIncludes
+0与-0的处理
在看代码的时候,有一段十分奇怪:
这段代码的意思是,在没有提供
comparator
的情况下,如果value === 0
,则将value
赋值为0
。value === 0
时,可能为+0
、-0
和0
,lodash 为什么要将它们都转为0
呢?后来看到 lodash 作者在 issue 中说,因为比较会用到
Set
,而Set
是不能区分+0
和-0
的。参考
Lodash系列——difference函数源码解析
value = (comparator || value !== 0) ? value : 0; does it work?
License
署名-非商业性使用-禁止演绎 4.0 国际 (CC BY-NC-ND 4.0)
最后,所有文章都会同步发送到微信公众号上,欢迎关注,欢迎提意见:
作者:对角另一面
The text was updated successfully, but these errors were encountered: