文章目录
数组是一种线性表数据结构。它用一组连续的内存空间,来存储一组具有相同类型的数据。

上图可以看出,数组的存储方式为连续的内存空间,那么几句可以通过下面的方式,
a[i]_address = base_address + i * data_type_size
实现高效的数组随机访问。中间操作就没那么高效了,因为要在中间的位置删除一个元素的话,后面的元素就都要向前移动一位,插入也是同样。下面具体来看一下JS数组。
创建数组的方式
- 使用Array构造函数
let colors1 = new Array();
let colors2 = new Array(20);//创建length为20的数组
let colors3 = new Array('red', 'yellow', 'blue'); //以参数中的值来构建数组
- 使用数组字面量表示法
let colors = ["red", "green"];
let values = [1,2,];//强烈不建议这样使用,这位这样可能会创建一个包含2或3项的数组
//在IE8以及更早的版本中,第三个值undefined,其他浏览器只包含1,2的数组
在使用数组字面量表示法的时候,不会调用Array构造函数(Firefox 3及更早版本除外)
- 使用Array.of方法将一组值,转为数组。
Array.of(3,11,8) // [3,11,8]
Array.of(3) // [3]
数组的length属性
这个属性不是只读的,可以设置这个属性,从数组的末尾移除或想数组中添加新项。
let colors = ['red','yellow', 'blue'];
colors.length = 2;
console.log(colors[2]) //undefined;
colors = ['red','yellow', 'blue'];
colors.length = 4;
console.log(colors[3]) // undefined;
colors = ['red','yellow', 'blue'];
colors[colors.length] = 'green';//位置3添加一种颜色
colors[colors.length] = 'brown';//位置4添加一种颜色
数组检测
- 对于一个网页或一个全局全局作用域而言,使用instanceof就能搞定。
value instanceof Array
- 如果网页中包含多个框架,那实际上就存在两个以上不同的全局执行环境,从而存在两个以上不同版本的Array构造函数。如果你从一个框架向另一个框架传入一个数组,那么传入的数组与第二个框架中原生创建的数组分别具有各自不同的构造函数。为了解决这个问题新增了Array.isArray方法,该方法目的是确定某个值是不是数组,而不管它到底在哪个全局执行环境中创建的。
Array.isArray(value)
if (!Array.isArray) {
Array.isArray = function(arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
}
// 也可以用这个方法检测数组,该方法不能检测非原生构造函数的构造函数名
转换方法
- toLocaleString()、toString()、valueOf()方法。其中toString()方法会返回由数组中每个值的字符串拼接而成的一个以逗号分隔的字符串,而调用valueOf()返回的还是数组。
let colors = ['red','yellow', 'blue'];
colors.toString() // red,blue,green
colors.valueOf() //['red','yellow', 'blue']
colors.toLocaleString() //['red','yellow', 'blue']
console.log(colors.toString()) // red,blue,green
alert(colors.valueOf()) // red,blue,green
console.log(colors.toLocaleString()) // red,blue,green
alert里面调用valueOf返回了字符串是因为alert要接受字符串参数,所以隐式调用了toString。toLocaleString表示在特定语言环境下的表示字符串,新的 locales 和 options 参数让应用程序可以指定要进行格式转换的语言,并且定制函数的行为,通常返回与toString相同的值。
- join()方法可以使用不同的分隔符,来构建这个字符串。
let colors = ['red','yellow', 'blue'];
console.log(colors.join('|')) // "red|yellow|blue"
- Array.from方法用于将两类对象转为真正的数组:类似数组的对象和可遍历(iterable)的对象
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
// ES5的写法
var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']
// ES6的写法
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
Array.from([1, 2, 3])
// [1, 2, 3] 如果参数是一个真数组,会返回一个一摸一样的新数组
该方法还接受第二个参数,(可选的)返回对数组每一项处理的结果,和(可选的)运行该函数的作用域对象–影响this的值
Array.from([1, 2, 3], (x) => x * x)
// [1, 4, 9]
类似栈的方法
- push(推入):可以接受任意数量的参数,然后返回修改后的数组的长度。
- pop(弹出): 可以从数组的末尾移除最后一项,减少数组的长度,返回删除的项。
类似队列的方法
- shift: 移除数组中的第一项,并返回该项,同时使数组长度减1。
- unshift: 在数组前端添加任意个元素,并返回数组的长度。 shift结合push,unshift结合pop可以像队列一样使用数组。
重排序方法
- reverse顾名思义,就是反转数组项的顺序,并返回排序后的数组;
- sort排序数组的方法,默认情况下,按照升序排列数组项,调用每个数组项的toString()方法,然后比较得到的字符串,确定如何排序。也可以接受一个函数。返排序后的数组。
[1,5,2,4,3].sort((prev,next)=>{
if(prev < next){
return -1 //返回负数,保持原位。
}else if(prev > next){
return 1 //返回正数,交换位置。
}else{
return 0 //返回负数,保持原位。
}
})
操作方法
- concat()这个方法会先创建当前数组的一个副本,然后将接受到的参数添加到这个副本的末尾,最后返回数新构建的数组。
let colors1 = ['red','yellow', 'blue'];
let colors2 = colors1.concat('white', ['black', 'green']);
console.log(colors1)//["red", "yellow", "blue"]
console.log(colors2)//["red", "yellow", "blue", "white", "black", "green"]
- slice()基于当前数组中的一个或多个项创建一个新数组,接受一或两个参数,既要返回的起始和结束位置。不会改变原数组。
let colors1 = ['red','yellow', 'blue'];
let colors2 = colors1.slice(0);
let colors3 = colors1.slice(0, 1);
console.log(colors2)//['red','yellow', 'blue'];
console.log(colors3)//['red'];
console.log(colors1 == colors2) //false
- splice()方法
- 删除
let color = ["red","green","blue"];
let removed = color.splice(0,1);
console.log(color); //["green","blue"]
console.log(removed);//["red"]
- 插入
removed = color.splice(1,0,"yellow","orange");
console.log(removed);//[]
console.log(color);//["green", "yellow", "orange", "blue"]
- 替换
removed = color.splice(1,1,"red","purple");
console.log(removed);//["yellow"]
console.log(color);//["green", "red", "purple", "orange", "blue"]
第一个参数起始位置,第二参数删除几个,第三个参数要插入的任意项。splice返回的是删除的项组成的数组,没有则返回空。
- copyWithin()方法将指定位置的成员复制到其他位置(会覆盖原有成员)。
// 将3号位复制到0号位
[1, 2, 3, 4, 5].copyWithin(0, 3, 4) // [4, 2, 3, 4, 5]
// -2相当于3号位,-1相当于4号位
[1, 2, 3, 4, 5].copyWithin(0, -2, -1) // [4, 2, 3, 4, 5]
接收三个参数,第一个是起始替换数据的位置,第二个是从该位置开始读取数据,第三个到该位置前停止读取数据。 5. fill()方法使用给定值,填充一个数组。
['a', 'b', 'c'].fill(7)
// [7, 7, 7]
new Array(3).fill(7)
// [7, 7, 7]
还可以接收第二和第三个参数,用于指定填充的起始位置和结束位置
['a', 'b', 'c'].fill(7, 1, 2)
// ['a', 7, 'c']
复制代码
位置方法
indexOf()和lastIndexOf()都接收两个参数:要查找的项和表示查找起点位置的索引。indexOf方法从数组的头部开始查找,lastIndexOf方法从数组的尾部开始查找。没找到则返回-1.
let arr = [1,2,3,2];
arr.indexOf(2)// 1
arr.lastIndexOf(2)// 3
arr.indexOf(4)// -1
这两个方法内部都是(===)来判断,所以会导致NaN误判。
findIndex()方法,返回第一个符合条件的数组成员位置,没找到返回-1,两个参数:每一项处理函数和(可选的)运行该函数的作用域对象
[1, 5, 10, 15].findIndex(function(value, index, arr) {//依次当前的值、当前的位置和原数组
return value > 9;
}) // 2
查值方法
find()方法。查找出第一个符合条件的数组成员,接收两个参数:一个遍历每一项的函数和(可选的)运行该函数的作用域对象
[1, 4, -5, 10].find((n) => n < 0) // -5
includes()返回一个布尔值,接收两个参数:要查找的项和表示查找起点位置的索引
[1, 2, 3].includes(2) // true
[1, 2, 3].includes(4) // false
[1, 2, NaN].includes(NaN) // true
[1, 2, 3].includes(3, 3); // false
[1, 2, 3].includes(3, -1); // true
flat()用于将嵌套的数组“拉平”,变成以为数组,返回一个新数组。接收一个参数,表示想要拉平的层数。
[1, 2, [3, [4, 5]]].flat() // [1, 2, 3, [4, 5]]
[1, 2, [3, [4, 5]]].flat(2) // [1, 2, 3, 4, 5]
[1, [2, [3]]].flat(Infinity) // [1, 2, 3] 不管多少曾,都要转成一维数组,可以 用Infinity参数。
迭代方法
every,filter,forEach,map,some,flatMap共6个迭代的方法,每个方法都接收两个参数:要在每一项上运动的函数和(可选的)运行该函数的作用域对象–影响this的值。
传入这些方法中的函数会接受3个参数:数组项的值,该项在数据中的位置和数组对象本身。 every():对数组中的每一项运行给定函数,如果该函数对每一项都返回true,则返回true,否则返回false。
let number = [1,2,3,4,5];
let everyResult = number.every((item, index, array)=>{
return item > 2
})
console.log(everyResult)// false
some():方法则是只传入的函数对数组中的某一项返回true,就会返回true。
let number = [1,2,3,4,5];
let someResult = number.some((item, index, array)=>{
return item > 2
})
console.log(someResult)// true
filter():方法利用指定的函数确定是否在返回的数组中包含某一项。例如要返回一个所有值都大于2的数组
let number = [1,2,3,4,5];
let filterResult = number.filter((item, index, array)=>{
return item > 2
})
console.log(filterResult)// [3, 4, 5]
map():也返回一个数组,而这个数组的每一项都是在原始数组中的对应项上运行传入函数的结果。
let number = [1,2,3,4,5];
let mapResult = number.map((item, index, array)=>{
return item * 2
})
console.log(mapResult)// [2, 4, 6, 8, 10]
forEach:它只是对数组中的每一项运行传入的函数。没有返回值。
flatMap()方法对原数组的每个成员执行一个函数,并对返回值执行flat()方法,返回一个新数组。
// 相当于 [[2, 4], [3, 6], [4, 8]].flat()
[2, 3, 4].flatMap((x) => [x, x * 2]) // [2, 4, 3, 6, 4, 8]
// 相当于 [[[2]], [[4]], [[6]], [[8]]].flat()
[1, 2, 3, 4].flatMap((x, index, array) => [[x * 2]]) // [[2], [4], [6], [8]]
//默认只能展开一层
归并方法
reduce从数组的第一项开始,逐个遍历到最后,reduceRight则从数组的最后一项开始,向前遍历到第一项。
这两个方法都接受两个参数:一个在每一项调用的函数和(可选的)作为归并基础的初始值。
let values = [1,5,4,7];
let sum = values.reduce((prev,cur,index,array)=>{ //这个函数的四个参数:前一个值,当前值,项的索引和数组对象
return prev+cur; //返回的任何值作为第一个参数自动传给下一项,第一次迭代发生在数组的第二项,因此第一个参数是数组的第一项,第二个参数是数组的第二项
});
console.log(sum);//17
------------------------------------------
slice,substr和substring的区别
正数:
首先,他们都接收两个参数,slice和substring接收的是起始位置和结束位置(不包括结束位置),而substr接收的则是起始位置和所要返回的字符串长度。直接看下面例子:
var test = 'hello world';
alert(test.slice(4,7)); //o w
alert(test.substring(4,7)); //o w
alert(test.substr(4,7)); //o world
这里有个需要注意的地方就是:substring是以两个参数中较小一个作为起始位置,较大的参数作为结束位置。
alert(test.substring(7,4)); //o w
等价于
alert(test.slice(4,7)); //o w
负数:
- slice() - 将传入的负参数与字符串长度相加;
- substring() - 把所有的负值置为0;
- substr() - 将负的第一个参数与字符串长度相加,负的第二个参数置为0。
var test = 'hello world';
alert(test.slice(-3)); //rld 11-3=8
alert(test.substring(-3)); //hello world
alert(test.substr(-3)); //rld
alert(test.slice(3,-4)); //lo w 3,11-4=7---3,7
alert(test.substring(3,-4)); //hel 3,0---0,3
alert(test.substr(3,-4)); //空字符串
以上示例的元算过程如下:
slice(-3) => slice(8)
substring(-3) => substring(0)
substr(-3) => substr(8)
slice(3, -4) => slice(3, 7)
substring(3, -4) => substring(3, 0) =>substring(0, 3)
substr(3, -4) => substr(3, 0)
总结:
正数:slice和substring一样,负数:各自不一样
注意数组也有一个方法是slice,用法类似
| 方法 | 参数 | 返回值 |
|---|---|---|
| slice(start, end) | start(必需) -起始位置;end(可选)-结束位置,若未指定,则默认到末尾所有元素 | 返回 [start,end)之间的元素 |
| substring(start, end) | start(必需) -起始位置;end(可选)-结束位置,若未指定,则默认到末尾所有元素 | 返回 [start,end)之间的元素 |
| substr(start, length) | start(必需)-起始位置;length(可选)-所截取的元素的个数,若未指定,则默认到末尾 | 返回[start, start+length)之间的元素 |
计算两个数组的交集、差集、并集、补集
最普遍的做法
使用 ES5 语法来实现虽然会麻烦些,但兼容性最好,不用考虑浏览器 JavaScript 版本。也不用引入其他第三方库。
var a = [1,2,3,4,5]
var b = [2,4,6,8,10]
//交集
var c = a.filter(function(v){ return b.indexOf(v) > -1 })
//差集
var d = a.filter(function(v){ return b.indexOf(v) == -1 })
//补集
var e = a.filter(function(v){ return !(b.indexOf(v) > -1) })
.concat(b.filter(function(v){ return !(a.indexOf(v) > -1)}))
//并集
var f = a.concat(b.filter(function(v){ return !(a.indexOf(v) > -1)}));
console.log("数组a:", a);
console.log("数组b:", b);
console.log("a与b的交集:", c);
console.log("a与b的差集:", d);
console.log("a与b的补集:", e);
console.log("a与b的并集:", f);
使用 ES6 语法实现
而在 ES6 中我们可以借助扩展运算符(…)以及 Set 的特性实现相关计算,代码也会更加简单些。
var a = [1,2,3,4,5]
var b = [2,4,6,8,10]
console.log("数组a:", a);
console.log("数组b:", b);
var sa = new Set(a);
var sb = new Set(b);
// 交集
let intersect = a.filter(x => sb.has(x));
// 差集
let minus = a.filter(x => !sb.has(x));
// 补集
let complement = [...a.filter(x => !sb.has(x)), ...b.filter(x => !sa.has(x))];
// 并集
let unionSet = Array.from(new Set([...a, ...b]));
console.log("a与b的交集:", intersect);
console.log("a与b的差集:", minus);
console.log("a与b的补集:", complement);
console.log("a与b的并集:", unionSet);
参考文章:
前半部分文章来源于:
https://juejin.cn/post/6844904007660470286#heading-11
计算两个数组的交集、差集、并集、补集:
https://www.hangge.com/blog/cache/detail_1862.htmlslice,substr和substring的区别:
https://www.jianshu.com/p/4d06661cf2b8
https://www.cnblogs.com/littledu/archive/2011/04/18/2019475.html
1万+

被折叠的 条评论
为什么被折叠?



