首页 前端知识 javascript/js中Array、Set、Map数据结构特性及用法

javascript/js中Array、Set、Map数据结构特性及用法

2024-10-26 09:10:42 前端知识 前端哥 19 781 我要收藏

前言

本文温习前端开发中常见的3种数据结构:数组Array、有序集合Set、有序映射Map,并分别介绍其特性、用法示例

数组-Array

适用于存放和读取有序集合、不要求集合元素唯一性时;可通过索引快速访问元素,实现元素增删改查时

使用方法

1.创建、修改

    // 直接创建
    let arr = [6,7,8,9,0];
    // 使用构造函数创建
    // arr = new Array(6,7,8,9,0);
    console.log('len:',arr.length); // len: 5
    // 得到数组长度要用length而不是size
    console.log('size:',arr.size) // size: undefined
    console.log(arr.at(0)); // 6
    console.log(arr[0]); // 6
    arr[0] = 100;  // 修改指定位置的元素
    console.log(arr); // [ 100, 7, 8, 9, 0 ]
    // fill(x,start?,end?)  从start索引开始填充元素x,end可选,end指定的位置不包含
    console.log(arr.fill(9999,2,4)); // [ 100, 7, 9999, 9999, 0 ]
    // 所有元素填充为 -1
    arr.fill(-1,0);
    console.log(arr); // [ -1, -1, -1, -1, -1 ]

2.添加删除元素

push添加,pop尾部删除,shift头部删除,unshift头部插入,concat合并数组

    let arr = [ 6, 7, 8, 9, 0 ]
    // push(x)尾部添加指定元素
    let len = arr.push(10);
    console.log("len:",len); // len: 6
    // pop() 尾部删除一个元素,并返回这个元素,若数组为空,返回undefined
    let lastVal = arr.pop();
    console.log("lastVal:",lastVal,", len:",arr.length); // lastVal: 10 , len: 5
    // shift() 头部删除一个元素,返回被删除元素,若数组为空返回undefined
    let delHeadVal = arr.shift();
    console.log("delHeadVal:",delHeadVal,",len:",arr.length); // delHeadVal: 6 ,len: 4
    // unshift(x1,x2,x3...)在元素开头插入一个或多个元素,返回插入后的数组长度
    len = arr.unshift(88);
    console.log("len:",len); // len: 5
    let arr2 = [2,4,6];
    // concat合并两个或多个数组,返回新的数组,注意arr不会发生改变
    let ansArr = arr.concat(arr2); 
    console.log("ansArr len:",ansArr.length); // ansArr len: 8

slice拷贝数组元素

    let nums = [1, 2, 3, 4, 5, 6, 7];
    // slice(start,exclusiveEnd) 包括start,不包括exclusiveEnd,返回一个新数组对象,该方法不会改变原始数组
    let sliceNums = nums.slice(1, 3);
    console.log("sliceNums:", sliceNums); // sliceNums: [ 2, 3 ]
    sliceNums[0] = 888;
    // 修改sliceNums,不会改变原始数组nums
    console.log("nums:", nums); // nums: [ 1, 2, 3, 4, 5, 6, 7 ]
    // 从索引5开始提取所有的元素 
    console.log(nums.slice(4)); // [5, 6, 7 ]
    // 易错提示:-1表示倒数第1个元素,由于exclusiveEnd不包括,因此得到的最后一个元素是倒数第2个元素
    console.log(nums.slice(5, -1)); // [ 6 ]
    // slice() 提取所有元素
    console.log(nums.slice()); // [ 1, 2, 3, 4, 5, 6, 7 ]
    // slice 超出索引范围,返回一个空数组 []
    console.log(nums.slice(88)); // []

splice修改、删除、插入元素

    let nums = [1, 2, 3, 4, 5, 6, 7];
    // 删除指定位置的N个元素: nums.splice(index,count) 从index位置开始连续删除count个元素,并返回删除的元素,nums本身被改变
    let removedNums = nums.splice(2, 5);
    console.log("removedNums:", removedNums, ", nums:", nums); // removedNums: [ 3, 4, 5, 6, 7 ] , nums: [ 1, 2 ]
    // 元素替换:从索引1处删除0个元素(返回为空),并对原始数组添加多个元素,原始数组被改变
    console.log("res:",nums.splice(1, 0, 'x', 'y', 'z')); // res: []
    console.log("splice nums:", nums); // splice nums: [ 1, 'x', 'y', 'z', 2 ]
    // 删除后续元素:删除从索引2开始的所有元素,返回被删除元素
    console.log("removed: ", nums.splice(2), "nums:", nums); // removed:  [ 'y', 'z', 2 ] nums: [ 1, 'x' ]
    nums = [1, 2, 3, 4];
    // 删除索引2处的元素
    console.log("del: ", nums.splice(2, 1),", nums:",nums); // del:  [ 3 ] , nums: [ 1, 2, 4 ]
    // 将索引2处的1个元素删除,并替换为78,88
    nums.splice(2, 1, 78, 88);
    console.log("nums:", nums); // nums: [ 1, 2, 78, 88 ]

3.筛选、查找元素

filter筛选,find查找元素,findIndex、indexOf、lastIndexOf查找元素索引,includes判断是否包含

    let nums = [1, 2, 3, 4, 5, 6, 7];
    // filter过滤出符合指定规则的元素
    let evenNums = nums.filter(x => x % 2 == 0); 
    // find查找数组中满足测试函数的第一个元素的值,若没有符合的,返回undefined
    console.log("evenNums:", evenNums); // evenNums: [ 2, 4, 6 ]
    let targetValue = nums.find(x => x > 5);
    console.log("targetvalue:", targetValue); // targetvalue: 6
    // findIndex返回符合测试元素的第一个索引,找不到返回-1
    let targetIndex = nums.findIndex(x => x > 5);
    console.log("targetIndex:", targetIndex); //targetIndex: 5
    // indexOf(x)从索引位置0开始寻找一个指定的元素,找到则返回指向第一个元素的索引,找不到则返回-1
    console.log("index:", nums.indexOf(5)); // index: 4
    // indexOf(x,fromIndex) 从index位置寻找一个元素x
    console.log(nums.indexOf(1, 5));  // -1
    // lastIndexOf(x,fromIndex) 若fromIndex缺省,默认从最后一个位置开始向前查找x元素的索引
    console.log(nums.lastIndexOf(5)) // 4
    // includes(x)判断数组中是否包含一个指定元素,若包含返回true,否则false
    console.log(nums.includes(4)); // true
    // includes(x,fromIndex) 从fromIndex位置开始查找是否包含指定元素
    console.log(nums.includes(2, 1)); // true

4.成分判断

every测试所有都符合、some测试至少一个元素符合

    let nums = [5, 8, 4, 6, 7];
    // every 判断所有元素是否都通过测试函数,若是返回true,否则false
    let isAllEven = nums.every(x => x % 2 == 0);
    console.log("isAllEven:", isAllEven); // false
    // some 判断是否至少有一个元素通过测试函数,若是返回true
    let hasEven = nums.some(x => x % 2 == 0);
    console.log("hasEven:", hasEven); // true

5.反转、排序

reverse反转数组顺序,sort排序

     let ids = new Array(2, 0, 3, 5, 1, 4);
     // reverse反转数组元素顺序,并返回数组本身
     let reverseIds = ids.reverse();
     console.log("reverseIds:", reverseIds); // reverseIds: [ 4, 1, 5, 3, 0, 2 ]
     console.log("ids:", ids); // ids: [ 4, 1, 5, 3, 0, 2 ]
     // sort排序会改变原始数组顺序,并返回数组本身,默认从小到大排序
     console.log(ids.sort()); // [ 0, 1, 2, 3, 4, 5 ]
     // 自定义排序,a-b升序,b-a降序
     ids.sort((a,b)=>b-a); 
     console.log(ids);// [ 5, 4, 3, 2, 1, 0 ]

6.元素遍历

for…in遍历索引,for…of遍历元素, forEach遍历元素及索引

   let nums = [5, 8, 4, 6, 7];
    // for...in遍历数组,遍历的是索引
    for (let index in nums) {
        console.log("index:", index, ", value:", nums[index]);
    }
    // for...of遍历数组,遍历得到的是具体元素
    for (let x of nums) {
        console.log("x=", x);
    }
    // forEach遍历元素
    nums.forEach(x => {
        console.log("x:", x);
    });
    // forEach两个参数时第2个元素是索引
    nums.forEach((x, index) => {
        console.log("x:", x, ", index:", index);
    });
    // 普通遍历方法
    for (let i = 0; i < nums.length; i++) {
        console.log("nusm:", nums[i]);
    }

7.累计、分组运算

reduce对数字元素进行算术累计运算,对字符串连接运算

    let nums = [1, 2, 3];
    let initVal = 0;
    // reduce对数组中每个元素执行一个函数,将结果汇总为单个值返回,initVal指定初始值,preVal+curVal表示将数组元素累加
    let sums = nums.reduce((preVal, curVal) => preVal + curVal, initVal);
    console.log("sums:", sums); // 6
    const words = ['Hello', 'World', 'JavaScript'];
    // reduce将元素连接为一个字符串
    const sentence = words.reduce((accumulator, currentValue) => accumulator + ' ' + currentValue);
    console.log("sentence:"+sentence); // sentence:Hello World JavaScript
    // join将所有元素用字符-连接为一个字符串
    let str = nums.join('-');
    console.log(str); // 1-2-3

reduce分组

  const users = [
    {name:"User-A",age:21},
    {name:'User-B',age:20},
    {name:'User-C',age:20},
    {name:'User-E',age:20}];
    let initVal = {};
    let ageGroup = users.reduce((preVal,curVal)=>{
        let age = curVal.age;
        if(!preVal[age]){
            preVal[age] = [];
        }
        preVal[age].push(curVal);
        return preVal;
    },initVal);
    console.log(ageGroup);
    // {
    //     '20': [
    //       { name: 'User-B', age: 20 },
    //       { name: 'User-C', age: 20 },
    //       { name: 'User-E', age: 20 }
    //     ],
    //     '21': [ { name: 'User-A', age: 21 } ]
    //   }

8.变换

map、flatMap将每个元素进行变换

    let nums = [1, 2, 3];
    console.log(nums.map(x=>'id-'+x)); // [ 'id-1', 'id-2', 'id-3' ]
    // map:对数组中的每个元素执行回调函数,回调函数的返回值作为元素
    let ans = nums.map(x=>[x*2]);
    console.log(ans); // [ [ 2 ], [ 4 ], [ 6 ] ]
    // flatMap: 对每个元素执行回调函数,并将结果展平一层后返回一个新数组,相当于先执行 map,然后再执行 flat
    let ans2 = nums.flatMap(x=>[x*2]);
    console.log(ans2); // [ 2, 4, 6 ]
    let nums2 = nums.map(x=>[x,x*x]);
    console.log(nums2); // [ [ 1, 1 ], [ 2, 4 ], [ 3, 9 ] ]
    let ans3 = nums.flatMap(x=>[x,x*x]); 
    console.log(ans3); // [ 1, 1, 2, 4, 3, 9 ]

有序集合-Set

用于存储具有唯一性的元素,常用于元素查找、去重场景

使用方法

1.元素去重

普通类型插入元素唯一,可用于元素去重,对象插入是否唯一根据引用判断

   let arr = [1,2,2,3,1];
    // 数组转为集合去重
    let setNums = new Set(arr); 
    // 集合转为数组
    console.log(Array.from(setNums)); // [ 1, 2, 3 ]
    let set = new Set();
    set.add(3);
    set.add(2);
    // 2已经存在,所以不会被重复添加
    set.add(2);
    // 获取集合大小要使用set.size,而不是set.length(输出为undefined)
    console.log("size:", set.size); // size: 2

2.元素存在

可以在内部表示为哈希表,查找时间复杂度为O(1)

    // set中是否含有某个元素
    let isContain = set.has(4);
    console.log("isContain:", isContain); // false

3.有序遍历

元素遍历时的顺序保持与插入顺序一致,可使用forEach或 for…of遍历

    let set = new Set([5,8,7,6]);
    // set集合的遍历应该使用 for...of而不是for...in,以下遍历什么也不会输出:
    // for(let id in set){
    //     console.log(id);
    // }
    // 遍历方法1:使用 for...of遍历
    for (let id of set) {
        console.log(id);
    }
    // 遍历方法2:使用forEach
    set.forEach(id => {
        console.log("id:", id);
    });
    // 获取迭代器对象,set.values()迭代器遍历,仍然要使用 for...of而不是for...in
    for (let value of set.values()) {
        console.log("value:", value);
    }
    //输出的 key和value其实是一样的
    for (let [key, value] of set.entries()) {
        console.log("key:", key, "value:", value);
    }

4.删除操作

delete删除某个元素,clear清空集合

    // delete 删除集合中数字5,成功返回true,否则false
    let isDel = set.delete(5);
    console.log("isDel:", isDel);
	set.clear();

有序映射-Map

Map 适合于频繁增删改键值对的场景,可确保的键唯一性,内部实现用的是哈希表,具有较好性能

使用方法

1.键值添加、更改

新增或修改set,取值get,判断存在has,删除delete

    let map = new Map();
    // set进行键值添加
    map.set("name", "Alice");
    map.set("age", 24);
    // 键已存在则会被更新
    map.set("name", "Blob");
    // 注意:Map不要使用[]操作符,这种设置属性的方式不会改变 Map 的数据结构,它使用的是通用对象的特性,因此使用has是查不到的
    // ap['gender'] = 'female';
    // console.log('! has:', map.has('gender')); // false
    console.log(map.has('name')); // true
    console.log(Array.from(map.entries())); // [ [ 'name', 'lisi' ], [ 1, 'apple' ] ]
    // 取与键关联的值,若不存在则返回undefined
    let value = map.get("name");
    console.log("value:", value); // value: Blob
    // 获取map大小使用size,而不是length
    console.log(map.size); // 2
    map.clear();

2.有序遍历

Map 的键是有序的,遍历输出保持与添加时的顺序一致

Map遍历for…of或forEach

    // 使用可迭代对象初始化Map
    let userMap = new Map([['id', 23], ['name', 'zhangsan'], ['age', 18]]);
    console.log(userMap);
    // for...of 遍历Map
    for (const [key, value] of userMap) {
        console.log("key:", key, ",value:", value);
    }
    // 或者
    for (const [key, value] of userMap.entries()) {
        console.log("key#:", key, ",value#:", value);
    }
    // 或者
    for (let entry of userMap) {
        console.log("entry:", entry);
        // entry[0]为键,entry[1]为值
        // console.log(entry[0],entry[1])
    }
    // forEach遍历map
    userMap.forEach((value, key) => {
        console.log("value=", value, ",key=", key);
    });
    for (const key of userMap.keys()) {
        console.log("key:", key);
    }
    for (const value of userMap.values()) {
        console.log('value:', value);
    }

关于Map映射与普通Object对象的区别

1.键的有序性:

Map 中的键以简单、直接的方式排序,Map 对象按照插入的顺序迭代条目、键和值

Object 的键排序比较复杂的,最好不要依赖属性的顺序

2.键的类型:

Map 的键可以为任何值(包括函数、对象或任何原始值)

Object 的键必须为 String 或 Symbol

3.大小计算:

Map 中的项目数量确定很容易从其 size 属性中获得

Object 中的项目数量确定比较麻烦,效率也较低,一种常见的方法是通过获取 Object.keys() 返回的数组的长度

4.其他方面:

Map 性能在涉及频繁添加和删除键值对的场景中表现更好,而Object未针对频繁添加和删除键值对进行优化

关于普通Object用法

// 普通对象
// 添加或修改属性obj[property],或obj.property,
// 遍历for...in(遍历key), for...of(遍历entries)

function testObject2() {
    // 创建一个空对象
    let obj = {};
    obj[2] = 'zhangsan';
    obj[1] = 'lisi';
    console.log(obj);
    obj.msg = "hello";
    console.log(obj);
    // 判断对象是否有某个属性
    console.log(obj.hasOwnProperty("msg")); // true
    console.log('msg' in obj); // true
    for (let key in obj) {
        console.log("key:", key, "value:", obj[key]);
    }
    // 遍历键值对
    Object.entries(obj).forEach((key, value) => {
        console.log("key:", key, ", value:", value);
    });
    for (const [key, value] of Object.entries(obj)) {
        console.log("key=", key, ", value=", value);
    }
    // 类似:Object.values(obj);
    Object.keys(obj).forEach(key => {
        console.log("key=", key);
    });
    // delete删除某个属性,删除后再访问该属性为undefined
    delete obj.msg;
    console.log(obj); // { '1': 'lisi', '2': 'zhangsan' }
    console.log(obj.msg); // undefined
    // 键的个数
    console.log(Object.keys(obj).length); // 2
}

参考资料

1.JavaScript 标准内置对象

2.JavaScript数据类型

转载请注明出处或者链接地址:https://www.qianduange.cn//article/19157.html
标签
评论
发布的文章
大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!