数组基础精讲
一、数组的基础结构和遍历
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