js系列-Array数组详解

创建声明数组

使用对象方式创建数组

    //基本类型创建时(回顾)
    let str = new String('abc');//创建字符串对象
    let bool = new Boolean(true);//创建Boolean类型对象
    let num = new Number(124);//创建数字对象
    //同前面讲的基本类型的创建一样,我们可以通多new创建对象的方式创建数组
    let arr = new Array('a', 'b', 'c', 'd');
    console.table(arr);

 

注意:使用对象方式创建数组时,如果元素时数字需要特别注意,new Array(3);所代表的意义: 

    let arr = new Array(1, 2, 3);
    console.log(arr);//[1,2,3]
    let ar = new Array(3);
    console.log(ar);//[undefined,undefined,undefined]
    //一个参数时,表示要创建的数组长度,而不是作为子元素。

    //当然我们也可以通过Array.of(3);来创建包含一个元素的数组
     let arr = Array.of(3);
     console.log(arr);//[3]
    //但但但我们更推荐下面字面量的方式创建数组

但我们更推荐使用字面量创建

const array = ["a", "b"];

 length属性可以获取数组元素数量

let arr= ["a", "b"];
console.log(arr.length); //2

//后端返回的数据不一定是数组可能为undefined或null,那么使用length属性就会报错,
//这是实际开发中经常遇到的问题,那么解决这个问题就要判断,其实我们应该养成习惯,
//对于接受的数据应加上判断处理,避免使用报错
arr && arr.length;//使用&&进行判断

Array方法

Array.isArray(arr);判断某个变量是否是一个数组对象

    let arr = [1,2,3];
    console.log(Array.isArray(arr));//true

Array.from(str);将类数组对象或者可迭代对象转换成数组

说明:1.类数组对象:有.length属性,例如DOM集合NodeList,arguments等,

    <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
    </ul>

<script>
    let lis = document.querySelectorAll('ul li');
    console.log(lis.length);//3
    //使用Array.from(arr);转成数组,就可以使用数组的遍历方法了
    Array.from(lis).map(item=>{
        console.log(item);//<li>1</li><li>2</li><li>3</li>
    });
    //使用展开语法(点语法)转成数组
    [...lis].map(item=>{
        console.log(item);//<li>1</li><li>2</li><li>3</li>
    })
</script>

2.可迭代对象:实现了[Symbol.iterator]方法的对象,例如字符串String 

    let str = '123';
    console.log(Array.from(str));//["1", "2", "3"]
    console.log(typeof str[Symbol.iterator] === 'function');//true

数组操作

push

从末尾压入一个或多个元素,直接改变原数组,返回值为数组元素数量 

    let arr = ['a','b'];
    let len = arr.push('c');
        len = arr.push('d','e');
    console.log(len);//5(返回值为数组长度)
    console.log(arr);//['a','b','c','d','e']

pop

从末尾弹出第一个元素,直接改变原数组,返回值为弹出的元素

    let arr = ['a','b'];
    let item = arr.pop();
    console.log(item);//'b'(返回值为弹出的元素)
    console.log(arr);//['a']
    //我们继续弹出元素,当数组没有元素是,pop的返回值就是undefined(可用于清空数组,下面会做讲解)
    console.log(arr.pop());//'a'
    console.log(arr.pop());//undefined

shift

方法从数组开始位置删除第一个元素,并返回该元素的值

    const array = [1, 2, 3];
    const firstElement = array.shift();
    console.log(array);// [2, 3]
    console.log(firstElement);// 1

unshift

将一个或多个元素添加到数组的开头,并返回该数组的新长度

    let arr = ['a','b'];
    let len = arr.unshift('c');
        len = arr.unshift('d','e');
    console.log(len);//5(返回值为数组长度)
    console.log(arr);//['d','e','c','a','b']

fill

用一个固定值填充一个数组中从起始索引到终止索引内的全部元素,不包括终止索引

arr.fill(value[, start[, end]]);
value:用来填充数组元素的值。

start :可选,起始索引,默认值为0。

end :可选,终止索引,默认值为 this.length

    const array = [1, 2, 3, 4];
    console.log(array.fill(0, 2, 4));//[1, 2, 0, 0] 把0填充到索引2和4之间,包括2,不包括4
    console.log(array.fill(5, 1));//[1, 5, 5, 5]
    console.log(array1.fill(6));//[6, 6, 6, 6]

说明:实际在开发中好像很少用到fill,但是可以用它模拟数据,比如大量重复数据;

    let obj = {title: '测试',num: 20};
    console.log(new Array(100).fill(obj));//[{title: '测试',num: 20},...]

slice

使用 slice 方法从数组中截取部分元素组合成新数组(并不会改变原数组),不传第二个参数时截取到数组的最后元素。

let arr = [0, 1, 2, 3, 4, 5, 6];
console.log(arr.slice(1, 3)); // [1,2]

//参数为负值
let arr = [0, 1, 2, 3, 4, 5, 6];
console.log(arr.slice(-1)); // [6]等价于arr.slice(arr.length - 1);
console.log(arr.slice(-2,-1)); // [5]等价于arr.slice(arr.length - 2,arr.length - 1);
console.log(arr.slice(-1,3)); // []如果第一个参数为负数,则第二个参数一定要为负数且大于第一个参数,否则截取不到元素

不设置参数是为获取所有元素

let arr = [0, 1, 2, 3, 4, 5, 6];
console.log(arr.slice()); //[0, 1, 2, 3, 4, 5, 6]

注意:slice截取是浅拷贝,即当数组元素是引用类型时,只是复制指针,如果改变截取的元素,则同时会改变原数组。

    let arr = [{title: '测试',num: 20},{title: 'test',num: 30}];
    let sArr = arr.slice(0,1);
    sArr[0].num = 100;
    console.log(sArr);//[{title: '测试',num: 100}]
    console.log(arr);//[{title: '测试',num: 100},{title: 'test',num: 30}];

 splice

删除、替换、添加数组中的元素,会对原数组进行改变,返回值为被删除的元素组成的数组

删除:第一个参数为从哪开始删除,第二个参数为删除的数量

    let arr = [0, 1, 2, 3, 4, 5, 6];
    console.log(arr.splice(1, 3)); //返回删除的元素 [1, 2, 3] 
    console.log(arr); //删除数据后的原数组 [0, 4, 5, 6]

替换:第一个参数为从哪开始,第二个参数为删除的数量,后面的所有参数为要放到该位置的元素

    let arr = [0, 1, 2, 3, 4, 5, 6];
    console.log(arr.splice(1, 1, 7, 8)); //返回被替换(删除)的元素 [1] 
    console.log(arr); //替换后的原数组  [0, 7, 8, 2, 3, 4, 5, 6]

添加:第一个参数为从哪开始,第二个参数设置为0,后面的所有参数为要添加该位置的元素

    let arr = [0, 1, 2, 3, 4, 5, 6];
    console.log(arr.splice(1, 0, 7, 8)); //返回被替换(删除)的元素 [] 
    console.log(arr); //替换后的原数组  [0, 7, 8, 2, 3, 4, 5, 6]

负值:第一个参数为负值,则表示从数组末位开始的第几位(等价于arr.length - n),第二个参数为负值表示不删除同0.

    let arr = [0, 1, 2, 3, 4, 5, 6];
    console.log(arr.splice(-1, -10, 7, 8)); //等价于arr.splice(arr.length-1, 0, 7, 8) 
    console.log(arr); //  [0, 7, 8, 2, 3, 4, 5, 6]

 清空数组

经过上面知识的学习,清空数组的方式大概有4种:

第一种改变变量的指向,指向空数组,即 arr = [];(当存在多个引用的时候,需要注意一些问题)

    let arr = [1, 2, 3];
    let array = arr;
    arr = [];
    console.log(arr);//[]
    console.log(array);//[1, 2, 3]

注意:经过上面的代码,我们会发现,将arr =[];后,array并没有改变,说明我们只是改变了arr的指向,将它指向[]空数组,但并没有改变真实数组,我们有图说明下:

 第二种将length置为0;(真正把数组清空)

    let arr = [1, 2, 3];
    let array = arr;
    arr.length = [];
    console.log(arr);//[]
    console.log(array);//[]

第三种使用splice

    let arr = [1, 2, 3];
    let array = arr;
    arr = arr.splice(0);
    console.log(arr);//[1, 2, 3]
    console.log(array);//[]

第四种使用pop/shift

    let arr = [1, 2, 3];
    let array = arr;
    while(arr.pop()){}//使用shift同理
    console.log(arr);//[]
    console.log(array);//[]

总结:只有第一种arr = []是只改变arr指向,其他三种方法都会改变内存中的真实数组。

join

将数组连接成字符串,可设置连接符

    let arr = [1, 2, 3];
    let str = arr.join();
    console.log(str);//'1, 2, 3'
    let string = arr.join('-');
    console.log(string);//'1-2-3'

split

将字符串分割成数组

    let str = '1-2-3';
    let arr = str.split('-');
    console.log(arr);//['1','2','3']注意这里元素是字符串

concat

连接合并两个或多个数组,元素是值类型的是复制操作,如果是引用类型还是指向同一对象

    let arr1 = [1, 2];
    let arr2 = [3, 4];
    let arr3 = [5, 6];
    let arr = arr1.concat(arr2, arr3);
    console.log(arr);//[1, 2, 3, 4, 5, 6]

展开语法(...)es6

上面说到用concat合并数组,我们有更清晰的方法,就是使用es6的展开语法

    let arr1 = [1, 2];
    let arr2 = [3, 4];
    let arr3 = [5, 6];
    let arr = [...arr1, ...arr2, ...arr3];
    console.log(arr);//[1, 2, 3, 4, 5, 6]

查找元素

数组包含多种查找的函数,包括查找元素,查找元素索引,判断元素是否存在。

indexOf

使用 indexOf 从前向后查找元素出现的位置,返回值是首个被找到的元素在数组中的索引位置; 若没有找到则返回 -1

    let arr = [2, 9, 4, 5, 2, 1];
    console.log(arr.indexOf(2));//0 从前面查找2出现的位置
    console.log(arr.indexOf(8));//-1

indexOf是严格相等,即值和值的类型必须都相同。

    let arr = [2, 9, 4, 5, '2', 1];
    console.log(arr.indexOf('2'));//4

第二个参数指定查找起始位置,若起始索引大于数组长度则查找不到返回-1,若起始索引为负数,例如为-2,则起始索引为arr.length-2

    let arr = [2, 9, 4, 5, 2, 1];
    console.log(arr.indexOf(2,1));//4 从前面第二个位置开始查找2出现的位置
    console.log(arr.indexOf(2,10));//-1
    console.log(arr.indexOf(2,-2));//4
    //等价于
    console.log(arr.indexOf(2,arr.length - 2));//4

lastIndexOf

与indexOf不同的是 lastIndexOf 从后向前查找元素出现的位置,返回值也是首个被找到的元素在数组中的索引位置;如果找不到返回 -1

    let arr = [2, 9, 4, 5, 2, 1];
    console.log(arr.lastIndexOf(2));//4 从后面开始查找2出现的位置

第二个参数指定查找开始位置,与indexOf不同的是,起始索引大于数组长度或为负数都是从最后开始查找,

    let arr = [2, 9, 4, 5, 2, 1];
    console.log(arr.lastIndexOf(2));//4 从前面第二个位置开始查找2出现的位置
    console.log(arr.lastIndexOf(2,10));//4
    console.log(arr.lastIndexOf(2,-2));//4
    //负数等价于
    console.log(arr.lastIndexOf(2,arr.length + 2));//4

includes (es6)

如果判断元素存不存在,使用includes就再合适不过了,就不用像indexOf还要判断是否等于-1,因为includes返回值就是Boolean,但includes只能用于基本类型的查找,下面我们介绍查找引用类型时使用find和findIndex

    let arr = [2, 9, 4, 5, 2, 1];
    console.log(arr.includes(4));//true
    console.log(arr.includes(6));//false

finde (es6)

查找元素并将查找到的第一个该元素返回

    let shop = [
        {id:1,name:'iMac',price:8000},
        {id:2,name:'iPad',price:3000},
        {id:3,name:'iPhon',price:7000}
    ];
    //回调函数三个参数分别为item当前元素,index当前元素索引,arr原数组
    let iPhon = shop.find((item,index,arr)=>{
        return item.name == 'iPhon';
    },{});//还可传递第二个参数,为执行回调时用作this 的对象。
    console.log(iPhon);//{id:3,name:'iPhon',price:7000}
    //使用includes是无法查找引用类型
    console.log(shop.includes({id:3,name:'iPhon',price:7000}));//false

 

 

findIndex

与find使用基本相同,不过返回值是数组中找到的元素的索引

    let shop = [
        {id:1,name:'iMac',price:8000},
        {id:2,name:'iPad',price:3000},
        {id:3,name:'iPhon',price:7000}
    ];
    let iPhonIndex = shop.findIndex((item,index,arr)=>{
        return item.name == 'iPhon';
    },{});
    console.log(iPhonIndex);//2

 

数组排序

reverse

将数组中元素的位置颠倒,并返回该数组,该方法会改变原数组。

    let arr = [1,2,4,5,6];
    let array = arr.reverse();
    console.log(array);//[6, 5, 4, 2, 1]
    console.log(arr);//原数组也被改变[6, 5, 4, 2, 1]

    let user = [{name:'张三'},{name:'李四'},{name:'王五'}]
    let reverseUser = user.reverse();
    console.log(reverseUser);//[{"name":"王五"},{"name":"李四"},{"name":"张三"}]

 

sort

默认排序顺序是在将元素转换为字符串,然后按照各个字符的Unicode位点进行排序

    let sArr = ['c','d','a','bb'];
    console.log(sArr.sort());//["a", "bb", "c", "d"]
    let arr = [2,10,4,33];
    console.log(arr.sort());//[10, 2, 33, 4]

指定排序函数:

    let shop = [
        {id:1,name:'iMac',price:8000},
        {id:2,name:'iPad',price:3000},
        {id:3,name:'iPhon',price:7000}
    ];
    /*排序遵循:
        返回负数 a 排在 b前面,从小到大
        返回正数 b 排在a 前面
        返回 0 时不动*/
    let sortShop = shop.sort((a,b)=>{
        return a.price - b.price;
    });
    console.log(sortShop);

 

循环遍历

for

    let arr = [1,2,4,5,6];
    for (let index = 0; index < arr.length; index++) {
        arr[index] = arr[index]+10;
    }
    console.log(arr);//[11, 12, 14, 15, 16]

forEach

除了抛出异常以外,没有办法中止或跳出 forEach() 循环,也就是使用break终止遍历会报语法错误

    let arr = [1,2,4,5,6];
    arr.forEach((item,index,array)=>{
        console.log(item);
        break;//Uncaught SyntaxError: Illegal break statement
    });

for ... in

for...in是为遍历对象属性而构建的,不建议数组使用(确切的说应该是数组禁止使用for/in遍历,因为遍历顺序有可能不是按照实际数组的内部顺序)

for ... of

遍历可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等)

这里有两个需要注意的问题,我们先来看代码:

    //问题一:可以循环中使用let和const定义变量,为什么可以使用const呢?
    //其实不管是用let还是const,每次循环都会创建了一个单独的变量
    //但要注意使用const定义变量时不可修改的
    let arr = [1, 2, 4, 5, 6];
    for (let item of arr) {
      console.log(item);
    }
    for (const item of arr) {
      // item = item + 1;//不可修改会报错
      console.log(item);
    }
    //问题二:如果元素是基本类型,修改遍历的值是不会修改原数组的
    //但如果是引用类型是可以修改原数组的
    let arr = [1, 2, 4, 5, 6];
    for (let item of arr) {
      item = item + 1;
    }
    console.log(arr);// [1, 2, 4, 5, 6]
    let shop = [
      { id: 1, name: 'iMac', price: 8000 },
      { id: 2, name: 'iPad', price: 3000 },
      { id: 3, name: 'iPhon', price: 7000 }
    ];
    for (let item of shop) {
      item.price = item.price + 1;
    }
    console.log(shop);// [{{ id: 1, name: 'iMac', price: 8001 },...}]

keys()

返回一个包含数组中每个索引键的Array Iterator对象。

    const arr = ['a', 'b', 'c'];
    const iterator = arr.keys();
    console.log(iterator);//Array Iterator {}

那么我们如何取出数组迭代对象中的值呢,我们除了使用for/of,还可以使用迭代对象next()方法

    const arr = ['a', 'b', 'c'];
    const iterator = arr.keys();
    // console.log(iterator);//Array Iterator {}
    // console.log(iterator.next());//{value: 0, done: false}
    // console.log(iterator.next());//{value: 0, done: false}
    // console.log(iterator.next());//{value: 0, done: false}
    // console.log(iterator.next());//{value: undefined, done: true}
    //我们发现next()返回值为对象,其中第一个值为key值,第二个值为是否迭代完成,可以使用while
    //这里使用到结构赋值
    while(({value, done} = iterator.next()) && done === false){
        console.log(value);
    }

 

values()

和keys()的唯一区别就是返回值为value组成的 Array Iterator 对象,使用和keys()完全相同。

entries()

返回一个新的Array Iterator对象,该对象包含数组中每个索引的键/值对

    const arr = ['a', 'b', 'c'];
    for (const item of arr.entries()) {
        console.log(item);//[0, "a"] [1, "b"]  [2, "c"] [2, "c"]
    }
    // 结构赋值
    for (const [key, value] of arr.entries()) {
        console.log(key, value);//0 "a" 1 "b" 2 "c"
    }

es6新增方法

every

数组内的所有元素是否都能通过某个指定函数的测试,它返回一个布尔值。

   let arr = [1,2,4,5,6];
   //数组中的元素是否全部大于0
   let isMin =  arr.every((item,index,array)=>{
        return item > 0;
    });
    console.log(isMin);//true

some

数组中是不是至少有1个元素通过了被提供的函数测试,它返回的是一个Boolean类型的值。

    let arr = [1,2,4,5,6];
    //数组中的元素是否存在大于4的项
    let isMin =  arr.some((item,index,array)=>{
        return item > 4;
    });
    console.log(isMin);//true

filter

过滤数组,返回值为满足条件的元素组成的新数组。

    let arr = [1,2,4,5,6];
    //过滤出于4的元素,组成新数组
    let newArr =  arr.filter((item,index,array)=>{
        return item > 4;
    });
    console.log(newArr);// [5, 6]

map

由返回值组成的新数组

    let arr = [1,2,4,5,6];
    // 原数组每个元素乘2,并返回组成新数组
    let newArr =  arr.map((item,index,array)=>{
        return item * 2;
    });
    console.log(newArr);// [2, 4, 8, 10, 12]
    console.log(arr);// [1, 2, 4, 5, 6]

reduce

参数:

callback

执行数组中每个值 (如果没有提供 initialValue则第一个值除外)的函数,包含四个参数:

  accumulator

      累计器累计回调的返回值; 它是上一次调用回调时返回的累积值,或initialValue(见于下方)。

  currentValue

      数组中正在处理的元素。

  index 可选

      数组中正在处理的当前元素的索引。 如果提供了initialValue,则起始索引号为0,否则从索引1起始。

  array可选

     调用reduce()的数组

initialValue可选

作为第一次调用 callback函数时的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错。

例子

数组里所有值的和

var sum = [0, 1, 2, 3].reduce(function (accumulator, currentValue) {
  return accumulator + currentValue;
}, 0);
// 和为 6

将二维数组转化为一维

var flattened = [[0, 1], [2, 3], [4, 5]].reduce(
  function(a, b) {
    return a.concat(b);
  },
  []
);
// flattened is [0, 1, 2, 3, 4, 5]

 计算数组中每个元素出现的次数

var names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];

var countedNames = names.reduce(function (allNames, name) { 
  if (name in allNames) {
    allNames[name]++;
  }
  else {
    allNames[name] = 1;
  }
  return allNames;
}, {});
// countedNames is:
// { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 }
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值