js array

数组是 js 中常见的对象,关于数组的操作很多,作为一个前端攻城狮,应该要能通过灵活应用其内置属性和方法,来解决一系列数组处理问题

初始化数组

  • 构造函数方法

var arr = new Array(3)

var arr = new Array('a','b','c')

var arr = Array(3)

  • 字面量方法 //无法指定成员个数

var arr = ['a','b','c']

数组检查和转化

检查数组类型

let arr = [];
// 1.ES5的isArray方法
Array.isArray(arr);

// 2.constructor指向对象实例的构造函数
arr.constructor === Array;

// 3.instanceof原理同2
arr instanceof Array;

// 4.利用Object的原型方法toString判断(必须是Object原型方法,array和function均重写了这个方法)
// toString方法返回反映这个对象的字符串
//可以用来区分各种类型,但是无法判断自定义对象类型,此时可用2.3方法判断自定义类型
Object.prototype.toString.call(arr) === "[object Array]";

数组转化问题

数组转 String—join(separator)
// 注意区别使用空格和空值
arr.join(" ");
String 转数组—split(separator)
// 根据separator来分割字符串,每一项作为数组的一个值
str.spilt(",");
对象转数组
let obj = { name: "jacksonzhou", age: 23 };
Object.keys(obj); // [name,age]
Object.values(obj); // ['jacksonzhou',23]
Object.entries(obj); // [[name,'jacksonzhou'],[age,23]]
数组转对象
Object.assign({},[1,2]) // 转成{0:1,1:1}
{...['a','b','c']} // 转成{0:'a',1:'b',3:'c'}
// es10的api,浏览器暂不支持
Object.fromEntries([name,'jacksonzhou'],[age,23])
类数组转化为数组

类数组定义:不具有数组所具有的方法,但具有 length 属性,其他属性值为非负整数;常见的类数组有 arguments 对象和 DOM 方法的返回结果(document.getElementsByTagName())

// 使用Array原型方法slice
Array.prototype.slice.call(arguments)
// from方法将类似数组或可迭代对象创建为数组
Array.from(arguments)
// ... (扩展运算符)将类数组扩展为一个列表??(列表实际上是啥?),再定义为数组。
[...arguments]
// 借助对象+indexOf,思路是遍历数组,将每一个值标记为属性,将出现一次的值加入新数组;
//一旦obj.indexOf(i)不为-1,说明重复了,不将它加入新数组

针对数组某项的操作

判断是否包含值

// indexOf
[1, 2, 3]
  .indexOf(2) // 1(其对应索引),不存在则为-1
  [
    // includes
    (1, 2, 3)
  ].includes(2) // true
  [
    // find
    (1, 2, 3)
  ].find((i) => {
    i === 3;
  }) // 3,无值返回undefined
  [
    // findIndex
    (1, 2, 3)
  ].findIndex((i) => {
    i === 3;
  }); //2,返回索引,无值返回-1

给每一项设置统一值

[1, 2, 3].fill(5); // [5,5,5]

每一项是否满足

[1, 2, 3].every((i) => {
  return i > 2;
}); // false

有一项满足

[1, 2, 3].some((i) => {
  return i > 2;
}); // true

计算每一项出现的次数

// 数组遍历+借助对象+属性标记+值计数

过滤数组

[1, 2, 3, 4, 5]
  .filter((i) => {
    return i > 2;
  }) // [3,4,5]
  [
    // 过滤空值
    (1, 2, null, 3, 0, false, 4, undefined, "", 5)
  ].filter(Boolean)
  [
    // [1,2,3,4,5],但不过滤空的引用类型,比如{}、[]
    ("1", "2", "3")
  ].map(parseInt) ===
  // 输出[1, NaN, NaN]
  ["1", "2", "3"].map((item, index) => parseInt(item, index));
  • 简易实现代码
Array.prototype.filterz = function (fn) {
  let arr = this;
  let newArr = [];
  for (let i = 0; i < arr.length; i++) {
    if (fn(arr[i])) {
      newArr.push(arr[i]);
    }
  }
  return newArr;
}[(1, 2, 3, 4, 5)].filterz((i) => {
  return i > 2;
});

重装数组

[1, 2, 3].map((i) => {
  return "我是" + i;
});

数组乱序

let arr = [1,2,3,4,5,6]
arr.sort(function(){
    return Math.random()-0.5
})

数组去重

Map 对象+过滤器 filter

Map 数据结构,它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键

function unique(arr) {
  const res = new Map();
  return arr.filter((a) => !res.has(a) && res.set(a, 1));
}

set(集合)去重

Set 数据结构,它类似于数组,但是成员的值都是唯一的,没有重复的值。

Array.from(new Set([1,2,2,3]))
[...new Set([1,2,2,3])]

直接使用数组去重

function unique2(arr) {
    let newArr = []
    for(let i=0;i<arr.length;i++){
        if(newArr.indexOf(arr[i])===-1)newArr.push(arr[i])
    }
    return newArr
}

对象数组去重

let json1 = [
  { id: 1, name: "a" },
  { id: 2, name: "b" },
  { id: 3, name: "c" },
];

let json2 = [
  { id: 1, name: "a" },
  { id: 2, name: "b" },
  { id: 4, name: "d" },
];

let json = json1.concat(json2); //两个数组对象合并
let newJson = []; //盛放去重后数据的新数组
for (item1 of json) {
  //循环json数组对象的内容
  let flag = true; //建立标记,判断数据是否重复,true为不重复
  for (item2 of newJson) {
    //循环新数组的内容
    if (item1.id == item2.id) {
      //让json数组对象的内容与新数组的内容作比较,相同的话,改变标记为false
      flag = false;
    }
  }

  if (flag) {
    //判断是否重复
    newJson.push(item1); //不重复的放入新数组。  新数组的内容会继续进行上边的循环。
  }
}

console.log("newJson", newJson);

扁平化数组

// flat是ES10的api, n表示维度, n为 Infinity 时维度为无限大
[[1,2],3].flat(2) // [1,2,3]
[1,[2,3,[4,[...]]]].flat(Infinity) // [1,2,3,4,...]
// 利用toString()实现
let arr = [1,[2,3,[4,5]]]
arr.toString().split(',').map(item=>{
    +item // 强制转换为数字类型
})
// 使用迭代的方式实现
let arr = [1, 2, [3, 4, 5, [6, 7], 8]]
function flat(arr) {
    while(arr.some(item => Array.isArray(item))){
        arr = [].concat(...arr) // 将数组型数值追加,并重复追加,知道没有数组型数据
    }
    return arr
}
flat(arr)
// 使用递归的方式实现
const flat = arr => arr.reduce((acc, cur) => (Array.isArray(cur) ? [...acc, ...flat(cur)] : [...acc, cur]), [])

排序

// sort--关于排序有太多算法知识点,这里只简单实现升序降序,后续再总结相关算法吧~
[1, 3, 2]
  .sort((a, b) => {
    a - b;
  }) // 升序
  [(1, 3, 2)].sort((a, b) => {
    b - a;
  }); // 降序

求最值

// Math.max/min
Math.max(...[1, 2, 3]); // ...将数组转化为参数列表,供max方法使用
Math.max.apply(this, [1, 2, 3])[
  // 利用apply可带数组参数
  // === Math.max.call(this,...[1,2,3])

  // reduce--累加器
  (1, 2, 3, 5)
].reduce((pre, cur) => {
  return Math.max(pre, cur);
}, 0);
// pre 指上一次return的值,cur指当前值,0指初始值

reducer 累加器原理

function reduce (arr, fn, initVal) {
  for (let i = 0; i < arr.length; i++) {
    initVal = fn(initVal, arr[i])
  }
  return initVal
}
let newArr = reduce(arr, (sum, cur) => {
  return sum + cur
}, 5)
console.log(newArr)

求和

// 遍历求和
let sum = 0;
[1, 2, 3].map((i) => {
  sum += i;
});
console.log(sum);
// reduce -- 累加器
let sum = [1, 2, 3].reduce((prev, current) => {
  return prev + current;
}, 0);
// 0 是初始值, prev 是先前return的值,current是当前值

合并

// concat--不会改变原数组,返回一个数组副本
let newArr = arr.concat([1,2,3])
// push--会改变原数组
arr.push([1,2,3])
// ...
[...[1,2,3],...[4,5]]

其他

  • 请把两个数组 [‘A1’, ‘A2’, ‘B1’, ‘B2’, ‘C1’, ‘C2’, ‘D1’, ‘D2’] 和 [‘A’, ‘B’, ‘C’, ‘D’],合并为 [‘A1’, ‘A2’, ‘A’, ‘B1’, ‘B2’, ‘B’, ‘C1’, ‘C2’, ‘C’, ‘D1’, ‘D2’, ‘D’]
// 先给第二个数组的值加个数字,让其能按顺序排序,然后再遍历数组去掉第二个数组的值加上的数字
let a1 =  ['A1', 'A2', 'B1', 'B2', 'C1', 'C2', 'D1', 'D2']
let a2 = ['A', 'B', 'C', 'D'].map((item) => {
  return item + 3
})

let a3 = [...a1, ...a2].sort().map((item) => {
  if(item.includes('3')){
    return item.split('')[0]
  }
  return item
})

栈和队列操作

栈操作

  • push()
  • pop()

队操作

  • push()
  • shift() // 区别一下 unshift()

扩展运算符…

  • 复制数组
let arr1 = [1, 2, 3];
let arr2 = arr1; // 仅是复制引用,修改arr2会影响arr1
let arr2 = [...arr1]; // 实际上等同于重新声明赋值
  • 转为函数参数
Math.max(...[-1, 1, 1001, -52]); // 1001