数组基础精讲

一、数组的基础结构和遍历

1、数组的基础结构

数组也是对象数据类型的,

console.log(typeof []);  // object

数组也有属性名,只不过属性名是数字,我们把数字属性名称之为它的索引:数组是以数字作为索引,索引从零开始,有一个length属性代表数组的长度。

数组基础精讲

2、类数组:类似于数组,但是不是数组。

(1) 通过getElementsByTagName获取的元素集合是类数组。

(2) 函数中的实参集合arguments 也是类数组。

浏览器控制台:

dir(document.getElementsByTagName('*'))

数组基础精讲

这就是一个类数组。 

数组基础精讲

arguments 也是一个类数组。 

3、遍历数组

FOR循环操作:

for (var i = 0;i < ary.length; i++) {
    console.log(ary[i]);
}

FOR IN循环操作

for (var key in ary) {
    // key:属性名(数组中的属性名是索引)
    console.log(ary[key]);
}

 使用FOR IN 的话,可以把数组原型上公共的属性给遍历到。

比如:

var ary = [12, 23, 34];

Array.prototype.aa = 100;

for (var key in ary) {
    // key:属性名(数组中的属性名是索引)
    console.log(ary[key]);
}

输出结果:

12
23
34
100

 FOR循环只能遍历到数组私有的一些属性,而FOR IN循环可以把一些自定义的公共属性也能遍历到。

 

二、数组方法-增加和删除以及修改

数组中有很多常用方法。

控制台输出:

console.log(Array.prototype);

一共有这么多方法:

数组基础精讲

我们要记住方法的这个几个维度。

(1) 方法的意义和作用

(2) 方法的形参

(3) 方法的返回值

(4) 通过此方法,原来的数组是否发生了改变

1、增加

第一种方式:push, 向数组的末尾追加新内容

参数:一到多个,任何数据类型都可以,想要给数组末尾追加什么,直接传递到push方法中即可,传递多个用逗号隔开。

返回值:新增后数组的长度。

原有数组改变了。

var ary = [12, 23, 34];

var result = ary.push(100);

console.log(result);  // 4

console.log(ary);     // [12, 23, 34, 100]

// 还可以追加多项内容
var result1 = ary.push('hello', 8, {name: 'hello'}, function () {});

console.log(result1);  // 8

console.log(ary);      // [ 12, 23, 34, 100, 'hello', 8, { name: 'hello' }, [Function] ]

第二种方式: unshift,向数组开头追加新内容

参数:需要追加的内容(可以是多个任何数据类型的值)

返回值:新增后数组的长度

原来数组改变了。

var ary = [12,23,34];

var result = ary.unshift(100);

console.log(result);  // 4

console.log(ary);     // [ 100, 12, 23, 34 ]

第三种方式:把数组当做一个普通的对象,使用对象键值对的操作,给其设置新的属性(索引)。

ary[ary.length] = xxx, 向数组的末尾追加了新的内容。

var ary = [12,23,34];

ary[ary.length] = 100;

console.log(ary);    // [ 100, 12, 23, 34, 100 ]

2、删除

第一种方式:pop,删除数组最后一项

参数:无

返回值:被删除的那一项内容

原有数组改变了

var ary = [12, 23, 34];

var result = ary.pop();

console.log(result);  // 34

console.log(ary);     // [ 12, 23 ]

第二种方式: shift,删除数组第一项

参数:无

返回值:被删除那一项的内容

原有数组改变了

var ary = [12, 23, 34];

var result = ary.shift();

console.log(result);   // 12

console.log(ary);      // [ 23, 34 ]

使用shift删除第一项之后,后面每一项的索引都要向前进一位。(导致后面项的索引发生改变)

第三种方式:delete,把数组当做普通的对象操作

delete ary[索引]  删除指定索引这一项。

当前项被删除后,原有数组其他项的索引不会改变。当前数组的length也不会改变。

删除第一项:

var ary = [12, 23, 34];

var result = delete ary[0];

console.log(result);   // true

console.log(ary);      // [ <1 empty item>, 23, 34 ]

删除最后一项:

var ary = [12, 23, 34];

var result = delete ary[ary.length-1];

console.log(result);   // true

console.log(ary);      // [ 12, 23, <1 empty item> ]

ary.length--  ,可以删除数组最后一项。

 

4、splice,数组中内置的方法,可以实现数组的增加、修改、删除。

splice 实现删除:

splice(n, m),从索引n开始删除m个。(m不写是删除到数组的末尾)

返回值: 被删除的内容(以一个新数组保存被删除的内容)

原有数组改变了

var ary = [12, 23, 34];
// 从索引1的位置,删除2位
var result = ary.splice(1,2);
console.log(result);   // [ 23, 34 ]
console.log(ary);      // [ 12 ]
var ary = [12, 23, 34];
// 从索引1的位置开始,删除到末尾
var result = ary.splice(1);
console.log(result);   // [ 23, 34 ]
console.log(ary);      // [ 12 ]
var ary = [12, 23, 34];
// 从索引0的位置开始,删除到末尾,就是清空数组,删除数组所有内容
var result = ary.splice(0);
console.log(result);   // [ 12, 23, 34 ]
console.log(ary);      // [  ]
var ary = [12, 23, 34];
// 不传任何内容,就是一项都不删除,返回一个新的空数组
var result = ary.splice();
console.log(result);   // []
console.log(ary);      // [ 12, 23, 34 ]

删除第一项:

var ary = [12, 23, 34];
// 删除第一项
var result = ary.splice(0,1);
console.log(result);      // [ 12 ]
console.log(ary);         // [ 23, 34 ]

 删除最后一项:

var ary = [12, 23, 34];
// 删除最后一项
var result = ary.splice(ary.length - 1);
console.log(result);      // [ 34 ]
console.log(ary);         // [ 12, 23 ]

 splice 实现修改:

splice(n ,m, x):在原有删除的基础上,用x代替删除的内容。

var ary = [12, 23, 34];
// 在原有删除的基础上,用hello代替删除的内容
var result = ary.splice(1, 1, 'hello');
console.log(result);   // [ 23 ]
console.log(ary);      // [ 12, 'hello', 34 ]

splice 实现增加:

 splice(n, 0, x): 在修改的基础上,我们一项都不删除,把x插入到索引n的前面。

var ary = [12, 23, 34];
// 一项都不删除,把hello插入到索引0的前面
var result = ary.splice(0, 0, 'hello');
console.log(result);   // [ ]
console.log(ary);      // [ 'hello', 12, 23, 34 ]
var ary = [12, 23, 34];
// 一项都不删除,把hello插入到数组的末尾
var result = ary.splice(ary.length, 0, 'hello');
console.log(result);      // [ ]
console.log(ary);         // [ 12, 23, 34, 'hello' ]
console.log(ary.length);  // 4
var ary = [12, 23, 34];
// 一项都不删除,把hello插入到末尾
var result = ary.splice(ary.length + 1, 0, 'hello');
console.log(result);      // [ ]
console.log(ary);         // [ 12, 23, 34, 'hello' ]
console.log(ary.length);  // 4
var ary = [12, 23, 34];
// 一项都不删除,把hello插入到索引为1的前面,也就是23的前面
var result = ary.splice(1, 0, 'hello');
console.log(result);   // [ ]
console.log(ary);      // [ 12, 'hello', 23, 34 ]

 

三、数组方法-数组的查询和拼接

1、slice,实现数组的查询

参数:slice(n, m),从索引n开始找到索引为m处。(不包含m)

返回值:把找到的部分以一个新数组返回

原来的数组不变

slice(n), 从索引n开始找到末尾

slice(0),或者 slice(),数组克隆,克隆一份和原来数组一模一样的新数组。

var ary = [12, 23, 34, 45, 56, 67, 78, 89, 90];
// 从索引为2的,找到索引为5的,(不包含索引为5的)
var result = ary.slice(2, 5);
console.log(result);      // [ 34, 45, 56 ]
console.log(ary);         // [ 12, 23, 34, 45, 56, 67, 78, 89, 90 ]
var ary = [12, 23, 34, 45, 56, 67, 78, 89, 90];
// 从索引为2的,找到末尾
var result = ary.slice(2);
console.log(result);      // [ 34, 45, 56, 67, 78, 89, 90 ]
console.log(ary);         // [ 12, 23, 34, 45, 56, 67, 78, 89, 90 ]
var ary = [12, 23, 34, 45, 56, 67, 78, 89, 90];
// 从索引为0的,找到末尾。 相当于找到所有。
var result = ary.slice(0);
console.log(result);      // [ 12, 23, 34, 45, 56, 67, 78, 89, 90 ]
console.log(ary);         // [ 12, 23, 34, 45, 56, 67, 78, 89, 90 ]
var ary = [12, 23, 34, 45, 56, 67, 78, 89, 90];
// 什么参数都不传,也是默认从索引为0的,找到末尾。 相当于找到所有。
var result = ary.slice();
console.log(result);      // [ 12, 23, 34, 45, 56, 67, 78, 89, 90 ]
console.log(ary);         // [ 12, 23, 34, 45, 56, 67, 78, 89, 90 ]

支持以负数为索引:

slice 支持负数索引,如果传递的索引为负数,浏览器解析的时候是按照,总长度+负数索引,来处理的。

var ary = [12, 23, 34, 45, 56, 67, 78, 89, 90];
// 支持以负数为索引。 
// 从倒数第4个(67),找到倒数第1个(90),不包含倒数第一个(90)。所以是 [67, 78, 89]
var result = ary.slice(-4, -1);
console.log(result);      // [ 67, 78, 89 ]
console.log(ary);         // [ 12, 23, 34, 45, 56, 67, 78, 89, 90 ]

2、concat,将多个数组拼接在一起

参数: 要拼接的内容(把内容放在原数组的后面),可以是一个数组,也可以是一些数据值。

返回: 拼接后的新数组

原有数组不变

concat() , 什么都没有拼接,相当于把原有数组克隆一份一模一样的新数组出来 。

var ary = [12, 23, 34, 45, 56, 67, 78, 89, 90];
// 将原有数组拼接多个数组或字符串。原有数组不改变。
var result = ary.concat([100, 200], [1000, 2000], 300, 'hello');
console.log(result);      // [ 12, 23, 34, 45, 56, 67, 78, 89, 90, 100, 200, 1000, 2000, 300, 'hello' ]
console.log(ary);         // [ 12, 23, 34, 45, 56, 67, 78, 89, 90 ]
var ary = [12, 23, 34, 45, 56, 67, 78, 89, 90];
// 不传任何参数,就会复制原有数组。
var result = ary.concat();
console.log(result);      // [ 12, 23, 34, 45, 56, 67, 78, 89, 90 ]
console.log(ary);         // [ 12, 23, 34, 45, 56, 67, 78, 89, 90 ]

 

四、数组方法-数组转换为字符串

1、 toString,实现把数组转化为字符串(转换后的字符串以逗号分隔每一项)

参数:无

返回值:转换的字符串

原有数组不变

var ary = [12, 23, 34, 45, 56, 67, 78, 89, 90];
// 实现把数组转化为字符串
var result = ary.toString();
console.log(result);      // 12,23,34,45,56,67,78,89,90
console.log(ary);         // [ 12, 23, 34, 45, 56, 67, 78, 89, 90 ]

2、join,把数组按照指定的分隔符转换为字符串,和字符串中的split相对应

参数:指定的连接符

返回值:转换后的字符串

原有数组不变

var ary = [12, 23, 34, 45, 56, 67, 78, 89, 90];
// 不传任何参数,默认以,分隔 
var result = ary.join();
console.log(result);      // 12,23,34,45,56,67,78,89,90
console.log(ary);         // [ 12, 23, 34, 45, 56, 67, 78, 89, 90 ]
var ary = [12, 23, 34, 45, 56, 67, 78, 89, 90];
// 传入 '' 时,没有分割
var result = ary.join('');
console.log(result);      // 122334455667788990
console.log(ary);         // [ 12, 23, 34, 45, 56, 67, 78, 89, 90 ]
var ary = [12, 23, 34, 45, 56, 67, 78, 89, 90];
// 指定分隔符,为一个空格
var result = ary.join(' ');
console.log(result);      // 12 23 34 45 56 67 78 89 90
console.log(ary);         // [ 12, 23, 34, 45, 56, 67, 78, 89, 90 ]
var ary = [12, 23, 34, 45, 56, 67, 78, 89, 90];
// 指定分隔符,为一个+号
var result = ary.join('+');
console.log(result);      // 12+23+34+45+56+67+78+89+90
console.log(ary);         // [ 12, 23, 34, 45, 56, 67, 78, 89, 90 ]

3、小技巧:数组求和

 已知数组中的每一项都是数字,想实现数组求和,我们如何实现?

(1) 循环实现

var ary = [12, 23, 34];
var total = null;
for (var i = 0; i < ary.length; i++) {
    total += ary[i];
}
console.log(total);  // 69

(2) join

evel:字符串变为JS表达式执行。

var ary = [12, 23, 34];
var total = eval(ary.join('+'));
console.log(total);  // 69

 

五、数组方法-数组中的排列和排序

1、reverse, 把数组中的每一项倒过来排列

参数: 无

返回值: 排序后的数组

原有数组改变了

var ary = [12, 23, 34, 45, 56, 67, 78, 89, 90];
var result = ary.reverse();
console.log(result);    // [ 90, 89, 78, 67, 56, 45, 34, 23, 12 ]
console.log(ary);       // [ 90, 89, 78, 67, 56, 45, 34, 23, 12 ]

2、sort,实现数组的排序

参数:无 或者 回调函数

返回值: 排序后的数组

原有数组改变了

不传递参数的情况下:可以给10以内的数字进行升序排列。但是超过10的就无法处理了。(多位数只识别第一位)

var ary = [1, 3, 2, 4, 2, 3, 4, 5, 3, 12, 1];
var result = ary.sort();
console.log(result);    // [ 1, 1, 12, 2, 2, 3, 3, 3, 4, 4, 5 ]
console.log(ary);       // [ 1, 1, 12, 2, 2, 3, 3, 3, 4, 4, 5 ]

升序:

var ary = [1, 3, 2, 4, 2, 3, 4, 5, 3, 12, 1];
var result = ary.sort(function(a,b) {return a-b;});
console.log(result);    // [ 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 12 ]
console.log(ary);       // [ 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 12 ]

降序:

var ary = [1, 3, 2, 4, 2, 3, 4, 5, 3, 12, 1];
var result = ary.sort(function(a,b) {return b-a;});
console.log(result);    // [ 12, 5, 4, 4, 3, 3, 3, 2, 2, 1, 1 ]
console.log(ary);       // [ 12, 5, 4, 4, 3, 3, 3, 2, 2, 1, 1 ]

六、数组方法-验证数组中是否包含某一项

1、indexOf 或者 lastIndexOf,获取当前项在数组中第一次或者最后一次出现位置的索引

数组中的这两个方法在IE6~8下不兼容,而字符串中的这两个方法兼容所有的浏览器(包含IE6~8)。

如果当前数组中并没有这一项,返回的索引是-1,我们根据这一点可以验证数组中是否包含这一项。

var ary = [1, 3, 2, 4, 2, 3, 4, 5, 3, 12, 1];
if (ary.indexOf(12) > -1) {
    // 数组中包含12
    console.log('包含12');
}

自己在数组原型上写一个方法,来实现indexOf的功能。

var ary = [1, 3, 2, 4, 2, 3, 4, 5, 3, 12, 1];

// 自己在数组原型上写一个公共方法
Array.prototype.myIndexOf = function myIndexOf(value) {
    var result = -1;
    // this指的是当前使用的那个数组
    // 用for循环数组中的每一项
    for (var i = 0; i < this.length; i++) {
        if (value === this[i]) {
            // 把索引返回给结果
            result = i;
            break;
        }
    }
    return result;
};
console.log(ary.myIndexOf(12));    // 9

 

七、数组方法-遍历数组的一些方法

因为用for循环数组,或者用for in循环数组。老写for循环就很麻烦。所以提供了两个方法来遍历数组中的每一项。

以下的方法在IE6~8下都不兼容。

1、forEach,遍历数组中的每一项

var ary = [1, 3, 2, 4, 2, 3, 4, 5, 3, 12, 1];

ary.forEach(function (value, index) {
    // 数组中有多少项,当前回调函数执行多少次。
    // 每一次传递进来的value就是当前遍历数组这一项的值, index就是遍历这一项的索引。
    console.log(value);  
});

2、map,遍历数组中的每一项,在forEach的基础上,可以修改每一项的值。

var ary = [1, 3, 2, 4, 2, 3, 4, 5, 3, 12, 1];

var newAry = ary.map(function (value, index) {
    // 数组中有多少项,当前回调函数执行多少次。
    // 每一次传递进来的value就是当前遍历数组这一项的值, index就是遍历这一项的索引。
    return 'xxx';  // return后面返回的结果就是把当前遍历的这一项修改为xxx
});

console.log(newAry);   // [ 'xxx','xxx','xxx','xxx','xxx','xxx','xxx','xxx','xxx','xxx','xxx' ]

还有filter,find,reduce,every。

八、数组去重-双循环遍历法

方案一:遍历数组中的每一项,拿每一项和它后面的项依次比较,如果相同了,则把相同的这一项在原来数组中删除即可。

var ary = [1, 2, 2, 2, 3, 2, 1, 2, 3, 2, 2, 3, 4, 3, 2, 2, 3];

// ary.length-1, 最后一项的后面没有内容了,我们不需要再比较
for (var i = 0; i < ary.length - 1; i++) {
    var cur = ary[i];  // 当前遍历的这一项(索引是i)
    // 把拿出的这一项和后面的每一项进行比较
    // 从当前项的后一项开始,所以 j = i+1
    // 把当前项和它后面项比较,当前项索引是i, 后一项索引是i+1
    for (var j = i + 1; j < ary.length; j++) {
        // ary[j],作比较的那一项
        if (cur === ary[j]) {
            // 本次作比较的这一项和当前项相同,我们需要在原有数组中把作比较的这一项删除掉(作比较这一项的索引是j)
            ary.splice(j, 1);
        }
    }
}

// 数组坍陷问题: 我们使用splice删除数组中的某一项后,删除这一项后面的每一项索引都要向前进一位(在原有索引上减一)
// 此时如果我们j++,循环操作的值累加了,我们通过最新j获取的元素,不是紧挨删除这一项的元素,而是跳过一项获取的
// 元素。
// 因为删除其中一项的时候,后面的索引都要向前提一位
console.log(ary);   // [ 1, 2, 2, 3, 3, 4 ]

正确写法:

var ary = [1, 2, 2, 2, 3, 2, 1, 2, 3, 2, 2, 3, 4, 3, 2, 2, 3];

// ary.length-1, 最后一项的后面没有内容了,我们不需要再比较
for (var i = 0; i < ary.length - 1; i++) {
    var cur = ary[i];  // 当前遍历的这一项(索引是i)
    // 把拿出的这一项和后面的每一项进行比较
    // 从当前项的后一项开始,所以 j = i+1
    // 把当前项和它后面项比较,当前项索引是i, 后一项索引是i+1
    for (var j = i + 1; j < ary.length; j++) {
        // ary[j],作比较的那一项
        if (cur === ary[j]) {
            // 本次作比较的这一项和当前项相同,我们需要在原有数组中把作比较的这一项删除掉(作比较这一项的索引是j)
            ary.splice(j, 1);
            // 防止数组坍陷问题。所以j--
            // 先让j--,然后再j++,相当于没加没减,此时j还是原有索引,再获取的时候
            // 就是删除这一项后面紧挨着的这一项
            j--;
        }
    }
}

console.log(ary);   // [ 1, 2, 3, 4 ]

 或者这样写:

var ary = [1, 2, 2, 2, 3, 2, 1, 2, 3, 2, 2, 3, 4, 3, 2, 2, 3];

// ary.length-1, 最后一项的后面没有内容了,我们不需要再比较
for (var i = 0; i < ary.length - 1; i++) {
    var cur = ary[i];  // 当前遍历的这一项(索引是i)
    // 把拿出的这一项和后面的每一项进行比较
    // 从当前项的后一项开始,所以 j = i+1
    // 把当前项和它后面项比较,当前项索引是i, 后一项索引是i+1
    for (var j = i + 1; j < ary.length;) {
        // ary[j],作比较的那一项
        if (cur === ary[j]) {
            // 本次作比较的这一项和当前项相同,我们需要在原有数组中把作比较的这一项删除掉(作比较这一项的索引是j)
            ary.splice(j, 1);
        } else {
            j++;
        }
    }
}

console.log(ary);   // [ 1, 2, 3, 4 ]

或者这样写:

var ary = [1, 2, 2, 2, 3, 2, 1, 2, 3, 2, 2, 3, 4, 3, 2, 2, 3];

// ary.length-1, 最后一项的后面没有内容了,我们不需要再比较
for (var i = 0; i < ary.length - 1; i++) {
    var cur = ary[i];  // 当前遍历的这一项(索引是i)
    // 把拿出的这一项和后面的每一项进行比较
    // 从当前项的后一项开始,所以 j = i+1
    // 把当前项和它后面项比较,当前项索引是i, 后一项索引是i+1
    for (var j = i + 1; j < ary.length;) {
        // ary[j],作比较的那一项
        // if (cur === ary[j]) {
        //     // 本次作比较的这一项和当前项相同,我们需要在原有数组中把作比较的这一项删除掉(作比较这一项的索引是j)
        //     ary.splice(j, 1);
        // } else {
        //     j++;
        // }

        cur === ary[j] ? ary.splice(j, 1) : j++;
    }
}

console.log(ary);   // [ 1, 2, 3, 4 ]

数组坍陷问题:我们使用splice删除数组中的某一项后,删除这一项后面的每一项索引都要向前进一位(在原有索引上减一),此时如果我们j++,循环操作的值累加了,我们通过最新j获取的元素不是紧挨删除这一项的元素,而是跳过一项获取的元素。

九、数组去重-indexOf处理

利用indexOf来验证当前数组中是否包含某一项,包含则把当前项删除掉。(不兼容IE6~8)。

var ary = [1, 2, 2, 2, 3, 2, 1, 2, 3, 2, 2, 3, 4, 3, 2, 2, 3];

for (var i = 0; i < ary.length; i++) {
    var cur = ary[i];  // 当前遍历的这一项
    var curNextAry = ary.slice(i+1);  // 把当前项后面的那些值以一个新数组返回,我们需要比较的就是后面的这些项对应的新数组
    // == -1表示不包含
    // > -1 表示包含
    if (curNextAry.indexOf(cur) > -1) {
        // 后面项组成的数组中包含当前这一项(当前这一项是重复的),我们把当前这一项删除掉即可
        ary.splice(i, 1);
        // 因为splice删除一项之后,后面的项索引会往前提一位
        // 所以相应的i也要减一位
        i--;
    }
}
console.log(ary);   // [ 1, 4, 2, 3 ]

 

十、数组去重-对象键值对处理

遍历数组中的每一项,把每一项作为新对象的属性名和属性值存储起来,例如:当前项1,对象中存储的{1:1}。 

在每一次存储之前验证一下当前对象中该属性是否存在,如果存在我们则不再存储并且把当前这个重复项删除掉即可。

如果不存在我们就存储进来即可。

怎么验证一个对象中有没有包含这个属性?

typeof obj[xxx] === 'undefined', 说明当前对象中没有xxx这个属性。如果已经存在这个属性,说明数组中的当前项是重复的,

(1) 在原有数组中删除这一项

(2) 不再向对象中存储这个结果,如果不存在(把当前项作为对象的属性名和属性值存储进去即可)

var ary = [1, 2, 2, 2, 3, 2, 1, 2, 3, 2, 2, 3, 4, 3, 2, 2, 3];

var obj = {};

for (var i = 0; i < ary.length; i++) {
    var cur = ary[i];
    if (typeof obj[cur] !== 'undefined') {
        // 说明对象中存在该属性,证明当前项是数组中的重复项
        ary.splice(i, 1);
        // 因为splice删除当前项之后,后面的索引会向前提一位。
        // 所以相应的i也要减一位。
        i--;
        continue;
    }
    // 存储, obj[1] = 1, 就是 {1:1}
    obj[cur] = cur;
}
console.log(obj);   // { '1': 1, '2': 2, '3': 3, '4': 4 }
console.log(ary);   // [ 1, 2, 3, 4 ]

或者这样写:(建议这样写)

var ary = [1, 2, 2, 2, 3, 2, 1, 2, 3, 2, 2, 3, 4, 3, 2, 2, 3];

var obj = {};

for (var i = 0; i < ary.length; i++) {
    var cur = ary[i];
    if (typeof obj[cur] !== 'undefined') {
        // 说明对象中存在该属性,证明当前项是数组中的重复项
        // 使用splice会导致后面的索引向前进一位,如果后面有很多项,消耗的性能很大
        // ary.splice(i, 1);
        // 因为splice删除当前项之后,后面的索引会向前提一位。
        // 所以相应的i也要减一位。
        // i--;

        // 思路:我们把最后一项拿过来替换当前要删除的这一项,然后再把最后一项删除。
        ary[i] = ary[ary.length - 1];
        // 再把最后一项删除掉
        ary.length--;
        // 还得从当前项去循环
        i--;
        continue;
    }
    // 存储, obj[1] = 1, 就是 {1:1}
    obj[cur] = cur;
}
console.log(obj);   // { '1': 1, '2': 2, '3': 3, '4': 4 }
console.log(ary);   // [ 1, 2, 3, 4 ]

 自己在数组原型上写一个公共的去重方法:

// 自己在数组原型上定义一个数组去重的方法
Array.prototype.myUnique = function myUnique() {
    var obj = {};
    // 遍历数组中的每一项
    // this就是当前使用的这个数组
    for (var i = 0; i < this.length; i++) {
        // 当前遍历的这一项
        var item = this[i];
        if (typeof obj[item] !== 'undefined') {
            // 把最后一项的值赋给当前这一项
            this[i] = this[this.length - 1];
            // 把最后一项给删除掉
            this.length--;
            // 循环还是从当前项开始,而不是下一项
            i--;
            continue;
        }
        // 存储到对象中去, obj[1] = 1, 相当于 {1:1}
        obj[item] = item;
    }
    // 清空obj
    obj = null;
    // 返回去重后的数组
    return this;
};

var ary = [1, 2, 2, 2, 3, 2, 1, 2, 3, 2, 2, 3, 4, 3, 2, 2, 3];

console.log(ary.myUnique());    // [ 1, 2, 3, 4 ]

// 而且还可以对去重后的数组进行排序
// 升序
console.log(ary.myUnique().sort(function (a, b) {
    return a - b;      // [ 1, 2, 3, 4 ]
}));

// 降序
console.log(ary.myUnique().sort(function (a, b) {
    return b - a;      // [ 4, 3, 2, 1 ]
}));

面试的时候, 建议使用这种方案。

 

十一、数组去重-扩展其他的去重方式

在真实项目中还有前后比较法。

扩展思路:

(1) 相邻法

首先给数组进行排序,然后相邻两项比较,相同的话,把后一项在数组中去掉。叫相邻比较法。

var ary = [1, 2, 2, 2, 3, 2, 1, 2, 3, 2, 2, 3, 4, 3, 2, 2, 3];

// 先排序,然后相邻比较
var newAry = ary.sort(function (a,b) {
    return a - b;
});

console.log(newAry);   // [ 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4 ]

十二、算法-冒泡排序

什么叫冒泡排序, 原理:让数组中的当前项和后一项进行比较,如果当前项大于后一项,我们让两者交换位置(实现的是由小到大的排序)。

每一轮从前到后两两比较,虽然不一定实现最后的排序效果,但是可以把当前最大的放在末尾。

具体比较的轮数:ary.length - 1, 数组有多长,我们只需要把总长度-1个数分别放在末尾,即可实现最后的排序。

17:05 

十三、算法-递归

十四、算法-快速冒泡

十五、算法-插入排序