别误会,Map不只是地图

2022-08-11 15:48:47 浏览数 (1)

上集说到ES6中set方法,在ES6中除了增加set方法之外,还考虑到一种场景——键值对的存储,而map集合就是专门存储多个键值对(key value pair)的数据。

在map出现之前,我们使用的是对象的方式来存储键值对,键是属性名,值是属性值。键值对数据结合的特点就是:键不可重复。如果用对象来存储键值对在某些场景下不太如意:

  1. 键名只能是字符串或者符号,这就给它的使用带来很大的限制
  2. 获取数据的数量不方便,如果想知道对象中存了多少个数据,就必须先拿到所有的键名,然后通过求数组的长度才能知道对象中有多少个属性。
  3. 键名容易跟原型上的名称冲突。

0、如何创建map

代码语言:javascript复制

 new Map();//创建一个没有任何内容的map集合

 new Map(iterable);//创建一个具有初始化内容的map,初始内容来自于可迭代对象每一次迭代的结果,
 //但是,它要求每一次迭代的结果必须是一个长度为2的数组,数组第一项表示键,数组第二项表示值

例:创建一个没有任何内容的map集合

代码语言:javascript复制
const mp = new Map();
console.log(mp);

执行结果:

例:创建一个有初始内容的map集合

代码语言:javascript复制
const mp = new Map([["a",1],["b",2],["c",3]]);
console.log(mp);

执行结果:

1、如何进行后续操作

「1、size:只读属性,获取当前map中键的数量」

例:size

代码语言:javascript复制
const mp = new Map([["a",1],["b",2],["c",3]]);
console.log(mp);
console.log("总数:",mp.size);

执行结果:

「2、set(键,值):设置一个键值对,键和值可以是任何类型」这也是跟Object存储的区别,对象只能是字符串

例:set()

代码语言:javascript复制
const mp = new Map([["a",1],["b",2],["c",3]]);
mp.set("d",4)
console.log(mp);

执行结果:

注意点

  1. 如果键不存在,则添加一项
  2. 如果键存在,则修改它的值
  3. 判断键存不存在的方式与set相同,都为Object.is()

例:请问下面map中有几个值?

代码语言:javascript复制
 const mp = new Map([["a",1],["b",2],["c",3]]);
       mp.set({},4);
       mp.set("a",abc);
       map.set({},00);
       console.log(mp);
       console.log("总数:",mp.size);

执行结果:

从结果看:有5个值,对象是引用值,它们的地址不同,所以不会覆盖,而a的原值1会被abc覆盖掉。如果说需要使用相同引用值对象,可以这样改:

代码语言:javascript复制
const mp = new Map([["a",1],["b",2],["c",3]]);
       const obj = {};
       mp.set(obj,4);
       mp.set("a","abc");
       mp.set(obj,00);
       console.log(mp);
       console.log("总数:",mp.size);

执行结果:

「3、get(键):根据一个键,得到一个值」

例:get(键)

代码语言:javascript复制
const mp = new Map([["a",1],["b",2],["c",3]]);
   
console.log("get('a')",mp.get("a"));

执行结果:

例:如果传入不存在的键

代码语言:javascript复制
const mp = new Map([["a",1],["b",2],["c",3]]);
   
console.log("get('a')",mp.get("jasnbdjka"));

执行结果:

「4、has(键):判断某个键是否存在」

例:has()

代码语言:javascript复制
 const mp = new Map([["a",1],["b",2],["c",3]]);
   
 console.log("has('a')",mp.has("a"));

执行结果:

「5、delete(键):删除指定的键,成功返回true,失败返回false

例:delete(键)

代码语言:javascript复制
const mp = new Map([["a",1],["b",2],["c",3]]);
   
console.log("delete('a')",mp.delete("a"));

执行结果:

「6、clear():清空map」

例:clear()

代码语言:javascript复制
const mp = new Map([["a",1],["b",2],["c",3]]);
console.log(mp);

2、如何与数组进行转换

例:数组转换成map集合

代码语言:javascript复制
//直接把数组放到 new Map(数组)就可以了
const mp = new Map(要转换的数组);
//如下:
const mp = new Map([["a",1],["b",2],["c",3]]);

例:map转换为数组

代码语言:javascript复制
//map本身也是一个可迭代的对象,每次迭代的结果就是每一项的值
const mp = new Map([["a",1],["b",2],["c",3]]);
const arr = [...mp];
console.log(arr);

执行结果:

3、遍历

  1. 使用for of循环,每次迭代得到的是一个长度为2的数组

例:for of

代码语言:javascript复制
   const mp = new Map([["a",1],["b",2],["c",3]]);
    
    for (const item of mp) {
        console.log(item);
    }

执行结果:

当然也可以直接解构

代码语言:javascript复制
    const mp = new Map([["a",1],["b",2],["c",3]]);
    //方式一:
    for (const [key,value] of mp) {
        console.log(key,value);
    }
    //方式二:
    for (const item of mp) {
        console.log(item[0],item[1]);
    }

执行结果:

  1. 使用forEach遍历
  • 参数1:每一项的值
  • 参数2:每一项的键
  • 参数3:map本身

例:forEach

代码语言:javascript复制
  const mp = new Map([["a",1],["b",2],["c",3]]);
        mp.forEach((value,key,that) =>{
            console.log(value,key,that);
        })

执行结果:

4、手写map

手写map方法跟浏览器提供的map方法是不一样的,因为我们没有办法调用底层代码,就当拓展思维了。

1、新建 myMap.js文件

代码语言:javascript复制
class MyMap {
    constructor(iterable = []) {
        //验证是否是可迭代的对象
        this.isIterator(iterable);
        this._datas = [];
        for (const item of iterable) {
            //item 也得是一个可迭代对象
            this.isIterator(item);

            //取出第一个迭代值和第二个迭代值
            const iterator = item[Symbol.iterator]();
            const key = iterator.next().value;
            const value = iterator.next().value;
            this.set(key, value);
        }

    }
    //判断是否是可迭代对象
    isIterator(target) {
        if (typeof target[Symbol.iterator] !== "function") {
            throw new TypeError(`${typeof target} ${target} is not is not iterable (cannot read property Symbol(Symbol.iterator))`);
        }
    }

    //set方法
    set(key, value) {
        const obj = this._getObj(key);
        if (obj) {
            //如果存在键名,则修改值
            obj.value = value;
        } else {
            this._datas.push({
                key,
                value
            })
        }

    }
    //delete
    delete(key) {
        for (let i = 0; i < this._datas.length; i  ) {
            const element = this._datas[i];
            if (this.isEqual(element.key, key)) {
                this._datas.splice(i, 1);
                return true;
            }
        }
        return false;
    }
    //get方法
    get(key) {
        const item = this._getObj(key);
        if (item) {

            return item.value;
        }
        return undefined;
    }

    //size方法
    get size() {
        return this._datas.length;
    }
    //has方法
    has(key) {
        return this._getObj(key) !== undefined; //不等于undefined,说明值找到了
    }
    //clear方法
    clear() {
        this._datas.length = 0;
    }
    //forEach
    forEach(callback) {
        for (const item of this._datas) {
            callback(item.value, item.key, this);
        }
    }

    /**
     * 根据key值从内部数组中,找到对应的数组项 
     * @param {*} key 
     */
    _getObj(key) {
        for (const item of this._datas) {
            if (this.isEqual(item.key, key)) {
                return item;
            }
        }
    }

    //使MyMap本身可迭代
    *[Symbol.iterator]() {
        for (const item of this._datas) {
            yield [item.key, item.value]
        }
    }


    /**
     * 判断两个数据是否相等
     * @param {*} data1 
     * @param {*} data2 
     */
    isEqual(data1, data2) {
        //如果data1和data2都等于0,那么我们认为它们相等
        if (data1 === 0 && data2 === 0) {
            return true;
        }
        return Object.is(data1, data2);
    }

代码测试:

代码语言:javascript复制
<script src="./js/myMap.js"></script>
<script>
    const mp = new MyMap([["a",1],["b",2],["c",3]]);
    console.log(mp);
</script>

例:set方法

例:forEach

代码语言:javascript复制
<script src="./js/yMap.js"></script>
<script>
    const mp = new MyMap([["a",1],["b",2],["c",3]]);
    mp.forEach((value,key,that) => {
        console.log(value,key,that);
    });

</script>

执行结果:

END

0 人点赞