1. 是否改变原数组的常用方法
1. 改变原数组的:
shift:将第一个元素删除并且返回删除元素,空即为undefined
unshift:向数组开头添加元素,并返回新的长度
pop:删除最后一个并返回删除的元素
push:向数组末尾添加元素,并返回新的长度
reverse:颠倒数组顺序
sort:对数组排序
splice:splice(start,length,item)删,增,替换数组元素,返回被删除数 组,无删除则不返回
2. 不改变原数组的:
concat:连接多个数组,返回新的数组
join:将数组中所有元素以参数作为分隔符放入一个字符
slice:slice(start,end),返回选定元素
map,filter,forEach,some,every等不改变原数组
2. 数组去重
let arr = [
1,
undefined,
2,
11,
NaN,
NaN,
"a",
1,
2,
3321,
4,
null,
4,
4,
null,
2,
"dd",
"a",
"d",
undefined
];
// # 方法1: es6的 new Set()方法 ==> (推荐)
Array.from(new Set(arr));
// 方法2: push方法。新建一新数组,遍历数组每一项,值若不在新数组就push进该新数组中
// 这种方法 NaN 无法去重
let newArr = [];
for (let i = 0; i < arr.length; i++) {
const ele = arr[i];
console.log(arr[i]);
if (newArr.indexOf(arr[i]) === -1) {
newArr.push(arr[i]);
}
}
console.log(newArr);
// 方法3: splice方法。 双重for循环, 若第二层循环跟第一层循环的值, 就通过arr.splice(j, 1)删除, 不要忘记j--
// NaN无法去重
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
if (arr[i] === arr[j]) {
arr.splice(j, 1);
j--;
}
}
}
// 方法4: 排序后相邻去除法, 会打乱原来数组的排序。 可以用split删除, 也可以用只push不与前一值重复的值两种方法
let sortArr = arr.sort();
console.log(sortArr);
console.log(sortArr.length);
let temp = [sortArr[0]];
for (let i = 0; i < sortArr.length; i++) {
// 方法1: splice方法 不能去重NaN
if (i < sortArr.length - 1 && sortArr[i] === sortArr[i + 1]) {
sortArr.splice(i + 1, 1);
i--;
}
// 方法2: push方法 如果sortArr[i]不与temp的最后一位相等, 就push进temp中。 不能去重NaN
if (sortArr[i] !== temp[temp.length - 1]) {
temp.push(sortArr[i]);
}
}
console.log(temp);
console.log(sortArr);
console.log(arr);
3. 数组浅拷贝和深拷贝
浅拷贝:只拷贝一层,深层次的对象级别只拷贝引用。 浅拷贝就是流于表面的拷贝方式;当属性值为对象类型时,只拷贝了对象数据的引用,导致新旧数据没有完全分离,还会互相影响
深拷贝:拷贝多层,每一级别的数据都会被拷贝出来。 拷贝之后新旧数据完全分离,不再共用对象类型的属性值,不会互相影响
1.浅拷贝的实现方式
// 方法1 通用循环
function shallowCopy(obj) {
if (typeof obj !== 'object') return;
//判断目标类型,来创建返回值
const newObj = obj instanceof Array ? [] : {};
for(let key in obj) {
//只复制元素自身的属性,不复制原型链上的
if (obj.hasOwnProperty(key)) {
newObj[key] = obj[key];
}
}
return newObj;
}
// 方法2 Object.assign
const newObj = Object.assign({}, oldObj);
// 方法3:Array.slice
const newArray = oldArray.slice();
// 方法4: Array.concat
const newArray = oldArray.concat();
//# 方法5: es6 (推荐)
const arr = [1, 2, 3]
const arrClone = [...arr]
// 对象也可以这样浅拷贝
const obj = { a: 1 }
const objClone = { ...obj }
2. 深拷贝的实现方式
const obj = {
info: {
name: 'kobe',
nums: [1,2,3]
},
persons: [person1, person2]
}
// 方法一:通用循环
function deepCopy(obj) {
if (typeof obj !== 'object') return;
const newObj = obj instanceof Array ? [] : {};
for(let key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = typeof obj === 'object' ? deepCopy(obj[key]) : obj[key];
}
}
return newObj;
}
// 方法二:JSON.stringify,JSON.parse 不能深拷贝属性值是函数的对象
// 在JSON.stringify的时候很多规则会使最后JSON.parse出来的对象不太一样。
const newObj = JSON.parse(JSON.stringify(oldObj));
总结: 一定要理解造成浅拷贝的原因:对象类型数据复制时,复制了引用地址,用的还是同一个数据对象;所以实现深拷贝的方式就是要对 对象类型属性值递归进行深拷贝,避免直接赋值。
4. 数组转对象的方法
1. es6新方法之 Object.assign();
let arr = [
{ user: "123" },
{ Cause: "22" },
{ EnterFactoryTime: "33" }
];
let res = Object.assign(...arr)
/*
arr = {
user: "123",
Cause: "22",
EnterFactiryTime: "33"
}
*/
let arr2 = ['a', 'c', 'ddd'];
let res2 = Object.assign({}, ['a', 'c', 'cfg'])
/*
arr2 = {
0: "a",
1: "d",
2: "d"
}
*/
5. 多维数组转一维数组的方法
let arr = [[1, [2, 9]], [3, 4, undefined, null], [5, 6, '', ' ']];
// 方法1: 利用arr.reduce(callback [, initialValue])
let arr1 = arr.reduce((a, b) => a.concat(b))
// 方法2: 利用apply
let arr2 = [].concat.apply([], arr);
// 方法3: 利用es6, 优点是 多维数组也可以
function flatten(arr) { return [].concat(...arr.map(x => Array.isArray(x) ? flatten(x) : x)) }
let arr3 = flatten(arr);
// 方法4: 通过将数组转变成字符串,利用str.split(','), 然后用map(Number)将字符串数组转整形实现。
//优点是多维数组也可以,缺点是数组元素都变字符串了。 会将数组中的空值全转为0。
let arr4 = (arr + '').split(",").map(Number);
// let arr4 = arr.toString().split(",").map(Number);
/* # 推荐 方法5: ES最新语法 Array.prototype.flat()。优点非常简单
语法:var newArray = arr.flat(depth),参数说明:depth,可选,指定嵌套数组中的结构深度,默认值为1。
可以写1,2,..., Infinity
Infinity展开所有嵌套数组 */
let arr5 = arr.flat()
let arr6 = arr.flat(2)
// 方法6 利用正则
let res7 = JSON.parse('[' + JSON.stringify(arr).replace(/\[|\]/g, '') + ']');
6. 判断是否为数组的方法
一共包含5种方法:
-
arr instanceof Array
-
Array.isArray(arr)
-
Object.prototype.toString.call(arr) === "[object Array]" 或者
{}.toString.call(arr) === "[object Array]" -
Array.prototype.isPrototypeOf(arr)
-
arr.constructor.toString().indexOf("Array") !== -1
// 一共包含5种方法
let arr = [1, 2, 3];
// 方法1: instanceof 返回布尔值
console.log(arr instanceof Array); // true
// 方法2: 原型prototype + toString + call();
console.log(Object.prototype.toString.call(arr)); //"[Object Array]"
console.log(Object.prototype.toString.call(arr).indexOf("Array") !== -1); // true
/* 方法3: 原型prototype + isPrototypeOf()
isPrototypeOf() 函数 : 用于指示对象是否存在于一个对象的原型链中。如果存在返回true,反之返回false。该方法属Object对象,由于所有的对象都继承了Object的对象实例,因此几乎所有的实例对象都可以使用该方法。如果variable的原型链中存在Array对象,就会返回true,也就说明variable是数组类型。 */
console.log(Array.prototype.isPrototypeOf(arr)); //true
// 方法4: 构造函数 constructor 注意下面的toString方法是带圆括号的
console.log(arr.constructor.toString()); // function Array() { [native code] }
console.log(arr.constructor.toString().indexOf("Array") !== -1); // true
// 方法5: 数组方法 isArray() ==>(推荐)
console.log(Array.isArray(arr)); //true
7. 判断数组是空数组[]的方法
方法1: 判断数组长度是否为0。
方法2: 使用JSON.stringify直接判断是否等于空数组的字符串
提示: 最好能先判断下是否是数组, 再用&&判断数组是空数组
let arr = [];
arr.length === 0; // true
JSON.stringify(arr) === "[]"; //true
8. 类数组转变成数组的6种方法
把符合以下条件的对象称为类数组
1、具有length属性
2、按索引方式存储数据
3、不具有数组的push、pop等方法
// 自定义一个伪数组
let likeArr = { 0: "伪", 1: "类", 2: "数", 3: "组", length: 4 };
console.log(Object.prototype.toString.call(likeArr) === '[object Object]'); // true
let arr = [];
console.log(Object.prototype.toString.call(arr) === "[object Array]"); // true
// 方法1: for循环赋值
for (let i = 0; i < likeArr.length; i++) {
arr[i] = likeArr[i];
}
// 方法2: for循环把伪数组每一项push到数组中
for (let i = 0; i < likeArr.length; i++) {
arr.push(likeArr[i]);
}
// 方法3: 空数组的call方法 (建议使用此方法)
arr = [].slice.call(likeArr);
// 方法4: 数组原型的call方法
arr = Array.prototype.slice.call(likeArr);
// 方法5: Array.from方法
arr = Array.from(likeArr);
// 方法6: 原型 __protp__
likeArr.__proto__ = Array.prototype;
9. 获取数组中的最大值和最小值
// 不能包含undefined和字符串 否则会转成NaN。 数组中的null , '' 会转换成0
let arr = [2, 5, 1, 11, 4214, "", null, " ", -1];
console.log("max:", Math.max.apply(this, arr)); // 4214
console.log("max2:", Math.max.call(this, ...arr)); // 4214
console.log("min:", Math.min.apply(this, arr)); // -1
console.log("min:", Math.min.call(this, ...arr)); // -1
10. 生成大量测试数据,类似[1,100]
测试大量数据的数组时可以这样生成:
// fill
const arr = new Array(100).fill(0).map((item, index) => index + 1)
// Array.from()
const arr = Array.from(Array(100), (v, k) => k + 1)
// ... + array.keys() 生成的是0-99的数组
const ary = [...Array(100).keys()]
new Array(100) 会生成一个有100空位的数组,这个数组是不能被map(),forEach(), filter(), reduce(), every() ,some()遍历的,因为空位会被跳过(for of不会跳过空位,可以遍历)。 [...new Array(4)] 可以给空位设置默认值undefined,从而使数组可以被以上方法遍历。
11. 数组取交集、差集、并集
const a = [0, 1, 2, 3, 4, 5]
const b = [3, 4, 5, 6, 7, 8]
// # 交集
1. const intersection = a.filter(v => b.includes(v)) // [3, 4, 5]
2. const duplicatedValues = [...new Set(a)].filter(item => b.includes(item)) // [3, 4, 5]
// # 差集
1. let difference = a.concat(b).filter(v => !a.includes(v) || !b.includes(v)) // [0, 1, 2, 6, 7, 8]
2. const diffValues = [...new Set([...a, ...b])].filter(item => !b.includes(item) || !a.includes(item)) // [0, 1, 2, 6, 7, 8]
// # 并集
const union = a.concat(b.filter(v => !a.includes(v))) // [0, 1, 2, 3, 4, 5, 6, 7, 8]