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 SetCache from './SetCache.js' import some from '../some.js' import cacheHas from './cacheHas.js'
《lodash源码分析之SetCache》 《lodash源码分析之some》 《lodash源码分析之cacheHas》
equalArrays 用来比较两个数组是否相等,这个相等不只是使用 === 来进行比较,也即不仅仅是指内存地址引用的相同,而是会深度比较,再来判断是否相等。
equalArrays
===
Stack
const isPartial = bitmask & COMPARE_PARTIAL_FLAG const arrLength = array.length const othLength = other.length if (arrLength != othLength && !(isPartial && othLength > arrLength)) { return false }
两个数组不相等,最简单的就是两个数组的长度不一样,那就没有相等的可能。
但是 isPartial 可以控制是否部分比较,部分比较要求 otherLength 的长度比 arrLength 的长度要长,也即只比较两者 0 - arrLength 部分的值。
isPartial
otherLength
arrLength
0 - arrLength
const stacked = stack.get(array) if (stacked && stack.get(other)) { return stacked == other } ... stack.set(array, other) stack.set(other, array) ... // 主要比较逻辑,可能会递归调用equalArrays stack['delete'](array) stack['delete'](other)
使用 stack 来保存 array 和 other ,可以看到,用 array 作为 key 时,值为 other 。
stack
array
other
key
因此 stack.get(array) 取到的会是 other 。
stack.get(array)
例如以下的数组,就会出现循环引用的情况:
const array = [1] const other = [1] array.push(array) other.push(ohter)
在第一次进入 equalArrays 时,stack.get(array) 是不会有值的。此时用 array 作为 key 来存 other ,用 other 作为 key 存 array ,后面会看到,这一点很巧妙。
再进入 equalArrays 时,上一轮的比较肯定是相等的,此时从 stack 中取出 array ,如果有值,则 array 肯定进入循环引用了,再从 stack 中取出 other ,如果有值,表示 other 也进入循环引用了,然后用 stacked 即上一轮的 other 值和当前的 other 值比较,如果相等,则表示 array 和 other 是相等的,因为上一轮已经和 array 比较过是相等的了。
stacked
最后还要从 stack 中删除。
处理完循环引用的比较,接下来就遍历 array ,逐个元素来比较了。
... let index = -1 let result = true const seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined ... while (++index < arrLength) { let compared const arrValue = array[index] const othValue = other[index] if (customizer) { compared = isPartial ? customizer(othValue, arrValue, index, other, array, stack) : customizer(arrValue, othValue, index, array, other, stack) } if (compared !== undefined) { if (compared) { continue } result = false break } }
如果有传自定义比较函数,则直接使用自定义比较函数进行比较,在部分比较模式下,othValue 和 arrValue 的位置是互调的。
othValue
arrValue
如果自定义比较函数返回的结果不是 undefined ,则使用自定义比较函数的结果,在假值的情况下直接跳出循环,得到的结果为 false。
undefined
false
在返回 undefined 的情况下,表示自定义比较函数希望使用内置的逻辑来进行比较。
if (seen) { if (!some(other, (othValue, othIndex) => { if (!cacheHas(seen, othIndex) && (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) { return seen.push(othIndex) } })) { result = false break } }
如果 seen 存在,表示要进行无序比较。
seen
上面的逻辑其实可以简化成:
if (!some(other, (othValue) => arrValue === othValue)) { return false }
其实就是判断每个 array 中每个值是否在都 other 中存在,如果都存在,则两个数组是相等的,否则就不相等
seen 是用来做缓存的,因此用 some 比较时,首先用 cacheHas 来判断当前值的索引是否存在于缓存中了,如果已经存在,则表示当前值已经比较过是相等的了,没必要再比较。
some
cacheHas
如果没有,没优先使用 === ,即全等的方式来比较,如果比较不出来,则再使用内部的比较函数 equalFunc 来比较,这个 equalFuc 即是 equalArrays 可能出现递归调用的原因。
equalFunc
equalFuc
如果相等,则将索引值存在入 seen 中,缓存起来。
else if (!( arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack) )) { result = false break }
有序比较就简单了,每次 while 循环的时候,使用 === 比较或者 equalFunc 比较即可。
while
署名-非商业性使用-禁止演绎 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源码分析之SetCache》
《lodash源码分析之some》
《lodash源码分析之cacheHas》
源码分析
equalArrays
用来比较两个数组是否相等,这个相等不只是使用===
来进行比较,也即不仅仅是指内存地址引用的相同,而是会深度比较,再来判断是否相等。参数
Stack
实例,用来防止出现循环引用的情况长度比较
两个数组不相等,最简单的就是两个数组的长度不一样,那就没有相等的可能。
但是
isPartial
可以控制是否部分比较,部分比较要求otherLength
的长度比arrLength
的长度要长,也即只比较两者0 - arrLength
部分的值。循环引用的比较
使用
stack
来保存array
和other
,可以看到,用array
作为key
时,值为other
。因此
stack.get(array)
取到的会是other
。例如以下的数组,就会出现循环引用的情况:
在第一次进入
equalArrays
时,stack.get(array)
是不会有值的。此时用array
作为key
来存other
,用other
作为key
存array
,后面会看到,这一点很巧妙。再进入
equalArrays
时,上一轮的比较肯定是相等的,此时从stack
中取出array
,如果有值,则array
肯定进入循环引用了,再从stack
中取出other
,如果有值,表示other
也进入循环引用了,然后用stacked
即上一轮的other
值和当前的other
值比较,如果相等,则表示array
和other
是相等的,因为上一轮已经和array
比较过是相等的了。最后还要从
stack
中删除。自定义比较函数
处理完循环引用的比较,接下来就遍历
array
,逐个元素来比较了。如果有传自定义比较函数,则直接使用自定义比较函数进行比较,在部分比较模式下,
othValue
和arrValue
的位置是互调的。如果自定义比较函数返回的结果不是
undefined
,则使用自定义比较函数的结果,在假值的情况下直接跳出循环,得到的结果为false
。在返回
undefined
的情况下,表示自定义比较函数希望使用内置的逻辑来进行比较。无序比较
如果
seen
存在,表示要进行无序比较。上面的逻辑其实可以简化成:
其实就是判断每个
array
中每个值是否在都other
中存在,如果都存在,则两个数组是相等的,否则就不相等seen
是用来做缓存的,因此用some
比较时,首先用cacheHas
来判断当前值的索引是否存在于缓存中了,如果已经存在,则表示当前值已经比较过是相等的了,没必要再比较。如果没有,没优先使用
===
,即全等的方式来比较,如果比较不出来,则再使用内部的比较函数equalFunc
来比较,这个equalFuc
即是equalArrays
可能出现递归调用的原因。如果相等,则将索引值存在入
seen
中,缓存起来。有序比较
有序比较就简单了,每次
while
循环的时候,使用===
比较或者equalFunc
比较即可。License
署名-非商业性使用-禁止演绎 4.0 国际 (CC BY-NC-ND 4.0)
最后,所有文章都会同步发送到微信公众号上,欢迎关注,欢迎提意见:
作者:对角另一面
The text was updated successfully, but these errors were encountered: