# 7、数组结构方法和去重(带上map和forEach共15个)
TIP
数组也是对象数据类型的 typeof [] // object
数组也有属性名,只不过属性名是数字,我们把数字属性名叫做索引
类数组:使用从零开始,且自然递增的整数做键名,并且定义了length表示元素个数的对象,我们就认为它是类数组对象;
数组中常用的方法
- 1.方法的意义和作用
- 2.方法需要的参数
- 3.方法的返回值
- 4.方法执行后原有数组是否改变
# 数组的增删
方法名 | 含义 | 参数 | 返回值 | 原有数组是否改变 |
---|---|---|---|---|
unshift | 将数据添加到一个数组的开头 | 新增加的内容 | 新增后数组的最新长度 | 变 |
push | 将数据添加到一个数组的末尾 | 一到多个,需要新增加的内容 | 新增后数组的最新长度 | 变 |
pop | 移出数组中最后一个元素 | 无 | 被删除的这一项内容 | 变 |
shift | 移出数组中第一个元素 | 无 | 被删除的这一项内容 | 变 |
也可以把数组当作普通对象,使用对象键值对的操作,给其设置新的属性(索引):
- 增加:ary[ary.length]=向数组的末尾追加了新的内容
- 删除:
- delete删除:
delete ary[索引]
删除指定索引这一项(当前项被删除后,原有数组其它项的索引不会改变;当前数组的length也不会改变;)- ary.length- -:删除数组最后一项
# 数组的修改
方法名 | 含义 | 参数 | 返回值 | 原有数组是否改变 |
---|---|---|---|---|
splice(n,m) | 从索引n开始删除m个元素 | n,m | 被删除的会以一个新数组返回 | 变 |
splice(n) | 从索引n开始删除到末尾 | n | 被删除的会以一个新数组返回 | 变 |
splice(0) | 清空数组 | 0 | 被清空的会以一个新数组返回 | 变 |
splice(n,m,x) | 从索引n开始用x替换m个元素,如果m为0,则表示把x增加到n的前面 | n,m,x | 被替换的会以一个新数组返回 | 变 |
# 数组的查询
方法名 | 含义 | 参数 | 返回值 | 原有数组是否改变 |
---|---|---|---|---|
slice(n,m) | 从索引n开始找到m处(不包含m) 注意 :某一项的话需要用项数减一来获取索引 | n,m | 把找到的部分以一个新数组返回 | 不变 |
slice(n) | 从索引n开始找到末尾 | n | 把找到的部分以一个新数组返回 | 不变 |
slice()/(0) | 克隆数组 | 0 | 克隆原有数组并以一个新数组返回 | 不变 |
slice支持负数索引,如果传递的索引为负数,浏览器解析的时候是按照 总长度+负数索引 来处理的,如果开始索引大于结束索引,则返回空数组
# 数组的拼接
方法名 | 含义 | 参数 | 返回值 | 原有数组是否改变 |
---|---|---|---|---|
concat(数组) | 用于连接两个或多个数组 | 一个或多个数组也可以是具体值 | 连接后的数组 | 不变 |
concat() | 克隆数组 | 无 | 克隆后的数组 | 不变 |
# 数组的转化
方法名 | 含义 | 参数 | 返回值 | 原有数组是否改变 |
---|---|---|---|---|
toString() | 把数组转换为字符串 | 无 | 数组的每一项在字符串中用逗号隔开(一个字符串) | 不变 |
join(符号) | 把数组的每一项按照指定连接符拼接成字符串 | 连接符 | 指定连接符拼接成的字符串 | 不变 |
var total = eval(ary.join('+')) // total = 数组中各项的和
# 数组的排序
方法名 | 含义 | 参数 | 返回值 | 原有数组是否改变 |
---|---|---|---|---|
reverse() | 用于颠倒数组中元素的顺序 | 无 | 颠倒后的数组 | 变为颠倒后的数组 |
sort() | 把数组进行排序 | 不填则只给10以下的数排序或填写函数 | 排序后的数组 | 变为排序后的数组 |
ary.sort(function(a,b){
return a-b; // 实现数组按升序排列
return b-a; // 实现数组按降序排列
})
// 实现原理:每次拿出数组中的当前项和后一项,每一次比较都会让匿名函数执行一次,不仅执行,而且还给匿名函数传递了两个参数a,b
// a:当前项
// b:当前项的后一项
// 在匿名函数中,如果return的结果是一个大于0的数,让a和b交换位置
// 如果return 的结果是一个小于等于0,则不交换;
// 注意:如果sort中什么都不填的话,默认会把数组元素转换为字符串,然后按照字符的UTF-16编码顺序来排序;
# 验证数组中是否包含某一项
# A.indexOf(B)/lastIndexOf
A.indexOf(B)/lastIndexOf
和字符串相同,获取B项在数组A中第一次/最后一次出现位置的索引,如果数组中没有这一项返回-1(不兼容IE6-8,在不考虑兼容的情况下,我们可以根据这个规律验证数组中是否包含某项) 兼容写法:
Array.prototype.myIndexOf = function(value){
var result =- 1;
for(var i = 0;i < this.length;i++ ){
if(value === this[i]){
result = i;
break;
}
return result;
}
}
# 遍历数组中的每一项
(ES5独有IE6-8不兼容)
# every()
every()
对数组中的每一项运行给定函数,如果该函数对每一项都返回 true ,则返回 true ,只要有一项返回false,就直接返回false; 注意:如果调用every方法的数组为一个空数组,那么不会运行传递的回调函数,直接返回true(此处涉及every的判别机制问题)
var numbers = [1,2,3,4,5,4,3,2,1];
var everyResult = numbers.every(function(item, index, array){
return (item > 2);
});
console.log(everyResult) // false
# some()
some()
对数组中的每一项运行给定函数,只要有一项运行函数后返回 true ,就直接返回 true ,否则返回false 注意:如果调用some方法的数组为一个空数组,那么不会运行传递的回调函数,直接返回false(此处涉及some的判别机制问题)
var numbers = [1,2,3,4,5,4,3,2,1];
var everyResult = numbers.some(function(item, index, array){
return (item > 2);
});
console.log(everyResult)//true
# filter()
filter()
对数组中的每一项运行给定函数,返回运行给定函数返回 true 的项组成的数组。
var numbers = [1,2,3,4,5,4,3,2,1];
var filterResult = numbers.filter(function(item, index, array){
return (item > 2);//如果没有符合的项,filterResult则是一个空数组
});
console.log(filterResult); // [3,4,5,4,3]
# forEach()
forEach()
对数组中的每一项运行给定函数。这个方法没有返回值。(本质上与for循环迭代一样) forEach:不修改原来的数组,无返回值 forEach:遍历数组中的每一项,不对原来的数组进行修改。不支持return,没有返回值。第二个参数表示传的是谁就把function中的this修改为谁,可不写默认为window
ary.forEach(function(value,index){
//=>数组中有多少项,当前回调函数执行多少次;每一次传递进来的value就是当前遍历数组这一项的值,index就是遍历这一项的索引
},this(可选))
# map()
map()
对数组中的每一项运行给定函数,返回是一个新的数组,数组中包含每次运行给定函数返回的结果。 map:不修改原来的数组,支持返回值(返回的是一个数组) map:和forEach非常相似,map 的回调函数中支持return返回值,return的是什么相当于把数组中这一项改为什么(但是并不改变原来的数组,只是相当于把原数组克隆了一份,修改了克隆的数组里面每一项的值) 第二个参数表示传的是谁就把function中的this修改为谁,可不写默认为window。
var numbers = [1,2,3,4,5,4,3,2,1];
var mapResult = numbers.map(function(item, index, array){
return item * 2;
});
console.log(mapResult); //[2,4,6,8,10,8,6,4,2]
ary.map(function(value,index){
//=>数组中有多少项,当前回调函数执行多少次;每一次传递进来的value就是当前遍历数组这一项的值,index就是遍历这一项的索引
return xxx; //=>RETURN后面返回的结果就是把当前遍历的这一项修改为xxx
});
// map执行完成后返回一个新的数组
以上方法都不会修改数组中的包含的值
# 归并方法:
# reduce(fn,initValue)和 reduceRight(fn,initValue)(IE6-8不兼容)
TIP
这两个方法都会循环数组的所有项,然后构建一个最终返回的值。都支持两个参数,第一个参数为循环每一次执行的回调函数,第二个参数为循环第一次的时候给的回调函数中prev的初始值;区别在于从哪头开始遍历数组,除此之外,它们完全相同; 注意:不设置初始值的时候,会把数组中的第一项的值赋给回调函数中的prev,从第二项开始循环,fn执行的次数为 数组的长度-1。如果设置了prev的初始值,就会从第一项开始循环。fn的执行次数为 数组的长度 每次循环执行回调函数都会默认传递四个参数prev, cur, index, array prev:上一次累积的值(前提是回调函数中必须有返回值,没有返回值则从第二次开始就是undefined) cur:当前循环的那一项 index:当前项的索引 array:原始数组
// 不设置初始值
var values = [1,2,3,4,5];
var sum = values.reduce(function(prev, cur, index, array){
return prev + cur;
});
console.log(sum);//15
// 获取两个对象中age相加的值(设置初始值相当于把第一次循环时prev的值设置为了0)
var values = [{name:'ceshi',age:9},{name:'ceshi',age:21}];
var sum = values.reduce(function(prev, cur, index, array){
第一次循环prev为0
return prev + cur.age;
},0);
console.log(sum);
# ES6中新增的数组方法
find(fn,this(可选)):返回数组中符合条件的项,不修改原来的数组
findIndex(fn,this(可选)):返回数组中符合条件的项的索引,不修改原来的数组
*这两个方法都可以接受第二个参数,用来改变回调函数fn中的this。*它的第一个参数是一个回调函数,回调函数支持三个参数依次为当前的值、当前的索引和原数组。所有数组成员依次执行该回调函数,直到找出第一个执行回调函数后返回值为true的成员,然后返回该成员,停止循环。findIndex返回的是符合条件的数组成员的索引,如果没有符合条件的成员(回调函数都返回false),find返回undefined,findIndex返回-1。
includes:返回一个布尔值,表示某个数组是否包含给定的值,
flat:用于将嵌套的数组“拉平”,变成一维的数组。该方法返回一个新数组,对原数据没有影响
# 数组的去重
思想:
- 1、双循环:拿数组中的每一项和它后面的每一项比较,如果相同则删除后面的那一项
for(var i=0;i<ary.length-1;i++){
var val=ary[i];
for(var k=i+1;k<ary.length;k++){//拿第一项从第二项开始作比较所以k从1开始
if(val===ary[k]){
ary.splice(k,1);
//splice会导致数组塌陷,即删除项后面的每一项的索引都会-1,此时j++会跳过删除项后面的第一项,从第二项开始比较
k--;//解决数组塌陷问题,相当于k没加没减继续拿
}
// val===ary[k]?ary.splice(k,1):k++;//这种方式也可以解决数组塌陷问题,需要把大循环中的i++删除,
}
}
- 2、用indexOf来验证当前数组中是否包含某一项,包含则把当前项删除掉(不兼容IE6-8);
function uniqe(ary) {
for (var i = 0; i < ary.length;) {
var cur = ary[i];
var val = ary.slice(i + 1);//当前项后面的项组成的一个新数组
val.indexOf(cur) > -1 ? ary.splice(i, 1) : i++;
}
return ary;
}
- 3、利用对象中属性名不能重复的原理,循环数组中的每一项,把每一项当做属性名在对象中验证其值是否存在(typeof obj[cur[i]]==='undefined'),如果在对象中不存在(true),把最后一项的值赋值给当前项,然后删除最后一项;
function oSort(ary) {
var obj={};
for(var i=0;i<ary.length;i++){
var cur=ary[i];
if(obj[cur]===cur){
ary[i]=ary[ary.length-1];
ary.length--;
i--;
continue;
}
obj[cur]=cur;
}
obj=null;
return ary;
}
- 4、先将原数组排序,排完序之后重复的项都会靠在一起,创建一个空的数组,然后把原数组中的第一项放到新数组中,然后循环原数组,从第二项开始,和新数组中的最后一项比较是否相等,如果不相等,则把原数组中的这一项添加到新数组的末尾,最后返回新数组即可;(有局限性:因为在去重之前会把原数组排序,所以会改变原来的数组)
Array.prototype.myUnique=function(){
var ary=this.sort(),
val=[];
val.push(ary[0]);
fot(var i=1;i<ary.length;i++){
var obj=ary[i];
if(obj!==val[val.length-1]){
val.push(obj);
}
}
return val;
}
# 冒泡排序
原理:
让数组中的当前项和后面的每一项进行比较,如果当前项大于后一项,我们让两者交换位置(小—大)
function bubble(ary) {
//->外层循环控制的是比较的轮数:
for (var i = 0; i < ary.length - 1; i++) {
//->里层循环控制每一轮比较的次数
for (var k = 0; k < ary.length - 1 - i; k++) {
//ary[k]:当前本次拿出来这一项
//ary[k+1]:当前项的后一项
if (ary[k] > ary[k + 1]) {
//当前项比后一项大,我们让两者交换位置
var temp = ary[k];
ary[k] = ary[k + 1];
ary[k + 1] = temp;
}
}
}
return ary;
}
每一轮从前到后两两比较,虽然不一定实现最后的排序效果,但是可以把当前最大的放在末尾 具体比较的轮数:ary.length-1 数组有多长,我们只需要把总长度-1个数分别放在末尾,即可实现最后的排序 对于数组[12, 13, 23, 14, 16, 11]; 第一轮比较5次:一共六个,不需要和自己比较 第二轮比较4次:一共六个,不用和自己比,也不用和第一轮放在末尾的那个最大值比 第三轮比较3次 每一轮比较的次数 ary.length-1(不用和自己比)-当前已经执行的轮数(执行一轮向末尾放一个最大值,这些值不需要再比较)
# 快速排序
原理
先找数组中的中间项,然后和其余项作比较,比中间项小的放在左边(新数组),大的放在右边(新数组);然后使用递归方法,把左边的数组和右边的数组再次调用快速排序,最后把递归后的结果(都是数组)连接起来并返回
function quick(ary){
//如果传进来的数组只有一项或者是空的,我们则不再继续取中间项拆分
if(ary.length<=1)return ary;
//获取中间项的索引:把中间项的值获取到,在原有数组中删除中间项
var oIndex=Math.floor(ary.length/2);
var val=ary.splice(oIndex,1)[0];//->splice返回的是个数组,数组中包含了删除的那个内容
//用中间项和数组中剩下的项作比较,比中间项大放在右边,小的放在左边(左右两边都是新数组)
var aryLeft=[],aryRight=[];
for(var i=0;i<ary.length;i++){
var cur=ary[i];
cur>val?aryRight.push(cur):aryLeft.push(cur);
}
//然后使用递归方法,把左边的数组和右边的数组也快速排序
//最后把递归后的结果(都是数组)和中间项连接起来,并返回
return quick(aryLeft).concat(val,quick(aryRight));
}
# 插入排序法
原理:
类似抓牌,先从数组中拿出一项(一般都是第一项)放在手中(一个新的空数组中),然后循环数组中剩下的项,和手中现有的项作比较,如果数组中的项比手中当前项小,就把数组中的项放在手中当前项的前面。如果数组中的项比手中当前项大,则不进行操作,进行下一次循环比较。如果数组中的项比手中最后一项还要大,则把数组中的项放在手中最末尾的位置;
function insert(ary) {
var handAry=[];
// 从数组中抽取第一项放到手中
handAry.push(ary[0]);
// 拿数组中剩余的项(i从1开始)和手中的项做比较
for (var i = 1; i <ary.length; i++) {
var val= ary[i];//数组中剩下的项
for (var k = 0; k <handAry.length; k++) {
// handAry[k]:当前比较的手里的牌
// 新抓的牌比当前比较的这张牌小,我们就把新抓的放在当前比较这张牌的前面
if(val<handAry[k]){
handAry.splice(k,0,val);
break;
}
// 如果数组中的项比较到了最后一项以上条件还未满足,则说明数组中的项比手中最后一项还要大,就把它添加到末尾
if(k===len-1){
handAry.push(val);
break;
}
}
}
return handAry;
}
# 数组排序+去重(自己总结的wihle循环方法)
function mySortAndUnique(ary) {
var obj={},val=[],len=ary.length;
//去重
while (len--){
obj[ary[len]]=ary[len];
}
// 利用对象属性的不重复性
for (var key in obj) {
if(obj.hasOwnproperty(key)){
val.push(obj[key]);
}
}
obj = null;
return val;
}
← 6、字符串方法(12个) 8、数据类型转换 →