# createAssigner
# Description
创建一个类似assign的函数。主要用在 merge 和 mergeWith
# Params
assigner - 合并值的函数。
# Return
Function
# Depend
import isIterateeCall from './isIterateeCall.js'
# Code
function createAssigner(assigner) {
return (object, ...sources) => {
let index = -1
let length = sources.length
let customizer = length > 1 ? sources[length - 1] : undefined
const guard = length > 2 ? sources[2] : undefined
customizer = (assigner.length > 3 && typeof customizer === 'function')
? (length--, customizer)
: undefined
if (guard && isIterateeCall(sources[0], sources[1], guard)) {
customizer = length < 3 ? undefined : customizer
length = 1
}
object = Object(object)
while (++index < length) {
const source = sources[index]
if (source) {
assigner(object, source, index, customizer)
}
}
return object
}
}
# Analyze
首先确定
customizer函数是否存在,这里判断sources的length是否大于1 ,也就是说在customizer函数之前至少是有一个 对象参与合并的,然后如果length大于1,先取source的最后一个值作为customizer的值紧接着判断
assigner的参数长度,也就是merge和mergeWith的区别,如果length大于 3,说明是mergeWith,是可以传入 自定义合并函数的如果同时 最先定义的
customizer为function类型 ,则会将sources的length减 1,也就是最后一个值为customizer不参与合并,同时使用 逗号操作符 返回customizer的值如果
assigner参数的长度小于等于3,或者第一步获取的customizer不是function类型,则将customizer置为undefined判断
guard,也就是判断sources[2]的值,如果guard存在,则同时判断 是不是属于某个迭代函数的参数,所以判断了sources[0],sources[1],sources[2]是否满足isIterateeCall如果满足了
isIterateeCall的条件,则将length置为 1,因为只需要拿到 迭代函数的第一个参数,也就是 当前的value值即可,不需要后面的参数iteratee函数 接受三个参数,当前值,当前值对应的key或者索引,原始数组或对象这里同时判断了
length < 3的情况,因为在之前已经判断了customizer函数是否存在,如果满足条件存在,length已经减一了,这里判断小于3原因在于isIterateeCall的判断,对于以下情况isIterateeCall判断会返回turefunction a () {} a['a'] = 1 console.log(isIterateeCall(1, 'a' , a)) // true但是这种情况下,
sources的参数只有 3 个也可以满足第二步的判断,如果不做< 3的判断来处理customizer,就可以导致错误的结果所以,如果刚好
sources的长度为 3,同时 这三个参数作为isIterateeCall的判断,也要判断 是否满足了 第二步 中判断customizer的条件,如果这两条都满足了,那就要判断length是否< 3, 如果小于3,那就证明,最后传入的函数 不是自定义函数,而是作为某个迭代的原始对象,不符合customizer的条件,要将customizer置为undefined最后一步就相对简单了,
while循环,然后取到每一个传入的真实对象参数,如果值存在,调用assigner函数进行合并即可
# Remark
- 逗号操作符 MDN (opens new window) 对它的每个操作数求值(从左到右),并返回最后一个操作数的值。
- Object.assign() MDN (opens new window) 方法用于将所有可枚举属性的值从一个或多个源对象分配到目标对象。它将返回目标对象。
# Example
const assigner = (object, source) => {
if (Array.isArray(object) && Array.isArray(source)) {
for (let k of source) {
object.push(k)
}
} else {
for (const k in source) {
object[k] = source[k]
}
}
}
const func = createAssigner(assigner)
const a = [1,2,3,4,5]
let b = [7]
func(b, a)
console.log(b) // [ 7, 1, 2, 3, 4, 5 ]