# 数组去重

# 双重 for

function unique(array) {
    var arr = [];

    for (var i = 0; i < array.length; i++) {
        for (var j = 0; j < arr.length; j++) {
            if (array[i] === arr[j]) {
                break;
            }
            if (j === arr.length) {
                arr.push(array[i]);
            }
        }
    }
}

var array = [1, 1, '1', '1'];
unique(array);  // [1, '1']

优点:兼容性好。

缺点:不能对 NaN 和 对象去重。

var array = [NaN, NaN];
unique(array);  //[NaN, NaN];
NaN 不等于 NaNvar array = [{a: 1}, {a: 1}]
对象 不等于 对象

# indexOf

用 indexOf 来简化内层 for 循环

function unique(array) {
    var arr = [];
    for (var i = 0; i < array.length; i++) {
        if (arr.indexOf(array[i]) === -1) {
            arr.push(array[i]);
        }
    }
}

优点:indexOf 比两层 for 性能要好。

缺点:不能对 NaN 和 对象去重。 在 indexOf 内部也是用 === 来判断的。

var array = [NaN, NaN];
unique(array);  //[NaN, NaN];
NaN 不等于 NaNvar array = [{a: 1}, {a: 1}]
对象 不等于 对象

# 排序去重

function unique(array) {
    var arr = [];
    var sortArray = [].concat().sort();
    var previous;
    for (var i = 0; i < array.length; i++) {
        if (!i || previous !== sortArray[i]) {
            arr.push(sortArray[i]);
        }
        previous = sortArray[i];
    }
}

优点:排序好再去比较要比 indexOf 更好。

缺点:对象和 NaN 不去重。 还是因为 === 的原因。

注意:sort 排序可能对有些类型是不能正常排序的。

# filter (简化外层循环)

var array = [1, 2, 1, 3];
function unique(array) {
    var res = array.filter((item, index, array) => {
        return array.indexOf(item) === index;
    })
    console.log(res);
}
unique(array);

我们需要判断当前元素从起点找是否还是原来的位置,如果是就代表第一次出现,我们就过滤出来,如果不是第一次出现,我们就开始下一次。

优点:简化了外层的 for 循环,效率要更好一点。

缺点:indexOf 内部也是使用全等,所以不能够判断 对象和 NaN 。

# 排序 + filter

function unique(array) {
    return array.concat().sort().filter((item, index, array) => {
        return !index || item !== array[index - 1];
    })
}

通过排序后,只需要对比前一个与后一个是否相等。

缺点:使用全等,所以不能够判断 对象和 NaN 。

# object 键值对

function unique() {
    var obj = {};
    return array.filter((item, index, array) => {
        return obj.hasOwnProperty(item) ? false : (obj[item] = true);
    })
}

缺点:1 和 ‘1’ 是会被转为字符串的,所以会判为同一个值, 也不能判断对象.

# 改进 object 键值对 (识别 1, ‘1’)

function unique(array) {
    var obj = {};
    return array.filter((item, index, array) => {
        return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true);
    })
}

可以辨别 1 , -1 。 存储格式为 {string1: '', number1: ''};

对象都会存为: {Object[object Object] : {}} 不能够识别对象。

# 改进 object 键值对 识别object

使用 JSON.stringify 将对象序列化。

function unique(array) {
    var obj = {};
    return array.filter((item, index, array) => {
        return obj.hasOwnProperty(typeof item + JSON.stringify(item)) ? false : (obj[typeof item + JSON.stringify(item)] = true);
    })
}

现在就可以识别两个对象来,但是 JSON.stringify 在序列的过程中,如果存在函数,正则表达式都会忽略。

# ES6

function unique(array) {
    return Array.from(new Set(array));
}

可以利用 Set 去重的特性,利用 Array.from 可以将类数组和可迭代对象转为数组。

对象不去重 NaN 去重. 它是能够识别 NaN 的。