最后来看看 underscore 对此的实现方式,underscore 将此封装到了 _.unique 方法中,调用方式为 _.unique(array, [isSorted], [iteratee])。其中第一个参数是必须的,是需要去重的数组,第二个参数可选,如果数组有序,则可以传入布尔值 true,第三个参数可选,如果需要对数组迭代的结果去重,则可以传入一个迭代函数。而数组元素去重是基于 === 运算符的。
其实很简单,underscore 中的实现方式和上面的方法一相似。
我们来看它的核心代码:
for (var i = 0, length = getLength(array); i < length; i++) { var value = array[i], // 如果指定了迭代函数 // 则对数组每一个元素进行迭代 computed = iteratee ? iteratee(value, i, array) : value; // 如果是有序数组,则当前元素只需跟上一个元素对比即可 // 用 seen 变量保存上一个元素 if (isSorted) { // 如果 i === 0,则直接 push // 否则比较当前元素是否和前一个元素相等 if (!i || seen !== computed) result.push(value); // seen 保存当前元素,供下一次对比 seen = computed; } else if (iteratee) { // 如果 seen[] 中没有 computed 这个元素值 if (!_.contains(seen, computed)) { seen.push(computed); result.push(value); } } else if (!_.contains(result, value)) { // 如果不用经过迭代函数计算,也就不用 seen[] 变量了 result.push(value); } }
外面的循环遍历数组元素,对于每个元素,如果数组有序,则和前一个元素比较,如果相同,则已经出现过,不加入到结果数组中,否则则加入。而如果有迭代函数,则计算传入迭代函数后的值,对值去重,调用 .contains 方法,而该方法的核心就是调用.indexOf 方法,和我们上面说的方法一异曲同工。