flatten
flatten
是用來實(shí)現(xiàn)數(shù)組扁平化的棚亩,并加入了shallow
函數(shù)strict
來表示是否只將數(shù)組進(jìn)行一次扁平化和是否對(duì)參數(shù)有嚴(yán)格要求。
然而我覺得官方的實(shí)現(xiàn)在效率上是有問題的。忽略shallow
和strict
,單看flatten本身的實(shí)現(xiàn)。
var flatten = function (input, shallow, strict, startIndex) {
var output = [],
idx = 0;
for (var i = startIndex || 0, length = input && input.length; i < length; i++) {
var value = input[i];
if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
//flatten current level of array or arguments object
if (!shallow) value = flatten(value, shallow, strict);
var j = 0,
len = value.length;
output.length += len;
while (j < len) {
output[idx++] = value[j++];
}
} else if (!strict) {
output[idx++] = value;
}
}
return output;
};
underscore源碼的實(shí)現(xiàn)中狞贱,對(duì)于嵌套數(shù)組中的元素,會(huì)進(jìn)入下一層flatten函數(shù)調(diào)用蜀涨;在這層調(diào)用中瞎嬉,所有數(shù)組會(huì)被推入output并返回上一層(output[idx++] = value;
);返回上一層后厚柳,又會(huì)遍歷一遍這個(gè)數(shù)組(while (j < len) output[idx++] = value[j++]
)氧枣。
也就是說,這相當(dāng)于將嵌套數(shù)組中的元素遍歷了兩遍别垮。
然而這種遍歷兩次并不是不能避免的便监。
// 忽略startIndex的實(shí)現(xiàn)
var flatten = function (input, shallow) {
var res = [];
(function fn(res, array, deep) {
array.forEach(item => {
if (isArrayLike(item) && (_.isArray(item) || _.isArguments(item))) {
if (shallow && deep) {
res.push(item);
} else {
fn(res, item, true);
}
} else {
res.push(item);
}
});
})(res, input, false);
return res;
}
我們將最終返回結(jié)果的引用res
在整個(gè)flatten
調(diào)用棧中都調(diào)用,凡是遇見非數(shù)組元素碳想,就將這個(gè)元素push
到res
中烧董;遇到數(shù)組,也只是進(jìn)入下一層調(diào)用中胧奔,將所有非數(shù)組元素推進(jìn)去逊移。這樣就可以避免非數(shù)組元素被遍歷兩次了。
2018.11.27更新:
Underscore源碼沒有問題……今早睡醒突然在想flatten
函數(shù)葡盗,發(fā)現(xiàn)我的遍歷是不能滿足strict
參數(shù)的……源碼應(yīng)該是為了滿足strict
參數(shù)所以才遍歷了兩遍螟左,沒毛病啡浊。