ES6 Map 数据结构

Map 定义与基本用法

     JavaScript 的对象(Object)本质上是键值对的集合(Hash 结构),但是传统上只能用字符串当作键,这给它的使用带来了很大的限制。

     为了解决这个问题,ES6 提供了 Map 数据结构,它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Map 对 象</title>

    <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
    <script type="text/javascript">
        /**map:创建一个 Map 对象
         * json:创建一个 json 对象*/
        let map = new Map();
        const json = {"name": "Hua An"};
        /**赋值:第一个 key 为对象 json,第二个 key 为字符串 "json" */
        map.set(json, 'content');
        map.set("json", json);

        console.log(map.get(json)); // 根据 key 取值:"content"
        console.log(map.has(json)); // 判断是否存在某个 Kye:true
        console.log(map.delete(json));//删除某个 key:true
        console.log(map.has(json)); // 判断是否存在某个 Kye:false
        console.log(map.get("json")["name"]);//根据 Key 取值,然后取 json 的值:Hua An
    </script>
</head>
<body>
<div id="myDiv"></div>
</body>
</html>

作为构造函数,Map 也可以接受一个数组作为参数,该数组的成员是一个个表示键值对的数组。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Map 对 象</title>

    <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
    <script type="text/javascript">

        /**创建一个 json 对象*/
        const json = {"name": "Hua An"};

        /**map:创建一个 Map 对象,同时初始化值*/
        const map = new Map(
                [
                    ['name', '张三'],
                    ['title', 'Author'],
                    ["user", json]
                ]);
        console.log(map.size);// 3
        console.log(map.has('name'));//判断是否存在某个 Kye: true
        console.log(map.get('name'));// 根据 key 取值:"张三"
        console.log(map.has('title'));// 判断是否存在某个 Kye:true
        console.log(map.get('title'));// 根据 key 取值:"Author"
        console.log(map.get("user")["name"]);// "Hua An"
    </script>
</head>
<body>
<div id="myDiv"></div>
</body>
</html>

事实上,不仅仅是数组,任何具有 Iterator 接口、且每个成员都是一个双元素的数组的数据结构都可以当作 Map 构造函数的参数。这就是说,Set 和 Map 都可以用来生成新的 Map 。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Map 对 象</title>
    <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
    <script type="text/javascript">
        let mapSource = new Map();
        mapSource.set("name", "华安");
        mapSource.set("title", "宁王造反");

        let map = new Map(mapSource);
        console.log(map.size);// 2
        console.log(map.get('name'));// 根据 key 取值:"华安"
        console.log(map.get('title'));// 根据 key 取值:"宁王造反"
    </script>
</head>
<body>
<div id="myDiv"></div>
</body>
</html>

如果对同一个键多次赋值,后面的值将覆盖前面的值,如果读取一个未知的键,则返回undefined。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Map 对 象</title>
    <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
    <script type="text/javascript">
        let map = new Map();
        map.set("name", "华安");
        map.set("name", "宁王造反");

        console.log(map.size);// 1
        console.log(map.get('name'));// 根据 key 取值:"宁王造反"
        console.log(map.get('title'));// 根据 key 取值:undefined
    </script>
</head>
<body>
<div id="myDiv"></div>
</body>
</html>

只有对同一个对象的引用,Map 结构才将其视为同一个键,Map 的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键。这就解决了同名属性碰撞(clash)的问题,我们扩展别人的库的时候,如果使用对象作为键名,就不用担心自己的属性与原作者的属性同名。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Map 对 象</title>
    <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
    <script type="text/javascript">
        let map = new Map();
        /**
         * 内存地址是不一样的,所以 k1 与 k2 是两个不同的对象
         * @type {string[]}
         */
        let k1 = ["name", "华安"];
        let k2 = ["name", "华安"];
        map.set(k1, "我是 k1");
        map.set(k2, "我是 k2");
        console.log(map.size);// 2
        console.log(map.get(k1));// 根据 key 取值:我是 k1
        console.log(map.get(k2));// 根据 key 取值:我是 k2
    </script>
</head>
<body>
<div id="myDiv"></div>
</body>
</html>

如果 Map 的键是一个简单类型的值(数字、字符串、布尔值),则只要两个值严格相等,Map 将其视为一个键,比如0和-0就是一个键,布尔值true和字符串true则是两个不同的键。另外,undefined和null也是两个不同的键。虽然NaN不严格相等于自身,但 Map 将其视为同一个键。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Map 对 象</title>
    <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
    <script type="text/javascript">

        let map = new Map();
        map.set(-0, 123);
        map.set(-5, 456);
        console.log(map.get(+0));// 123
        console.log(map.get(5));// undefined
        console.log(map.get(-5));// 456

        map.set(true, 1);
        map.set('true', 2);
        console.log(map.get(true));// 1
        console.log(map.get("true"));// 2

        map.set(undefined, 3);
        map.set(null, 4);
        console.log(map.get(undefined));// 3
        console.log(map.get(null));// 4

        map.set(NaN, 123);
        console.log(map.get(NaN));// 123
    </script>
</head>
<body>
<div id="myDiv"></div>
</body>
</html>

Map 属性与方法

size 属性返回 Map 结构的成员总数:

let map = new Map([
    ["name", "华安"],
    ["age", 35]
]);
console.log(map.size);//输出 2

let map2 = new Map();
console.log(map2.size);//输出 0 

set(key,value) 方法设置键名 key 对应的键值为 value,然后返回整个 Map 结构。如果 key 已经有值,则键值会被更新,否则就新生成该键:

let map = new Map();
map.set("name", "张三");
map.set(123, "age");
map.set(undefined, "未定义");

console.log(map);//输出 {"name" => "张三", 123 => "age", undefined => "未定义"}

/**set方法返回的是原 Map 对象,所以可以链式编程*/
map.set("name", "华安").set(123, "年龄");
console.log(map);//输出 {"name" => "华安", 123 => "年龄", undefined => "未定义"}

get(key) 方法读取 key 对应的键值,如果找不到 key,返回 undefined:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <title>ES6 测试</title>
    <!-- JQuery CDN-->
    <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>

    <script type="module">
        $(function () {
            let map = new Map();
            map.set("name", "华安").set("age", 35);
            map.set("address", "苏州");

            console.log(map.get("name"), map.get("age"), map.get("address"), map.get("birthday"));
            //输出:华安 35 苏州 undefined
        });
    </script>
</head>
<body>
</body>
</html>

has(key) 方法返回一个布尔值,表示某个键是否在当前 Map 对象之中:

let map = new Map();
map.set("name", "华安").set("age", 35);
map.set(110, "公安局");

console.log(map.has("name"), map.has("age"), map.has(110));//输出:true true true
console.log("abc");//输出:false

delete(key) 方法删除某个键,返回 true。如果删除失败,返回 false:

let map = new Map();
map.set("name", "华安").set("age", 35);
map.set(110, "公安局");

console.log(map.has("name"), map.has("age"), map.has(110));//输出:true true true
console.log(map.delete("name"));//输出:true
console.log(map.delete(110));// 输出:true
console.log(map.has("name"), map.has("age"), map.has(110));//输出:false true false

clear 方法清除所有成员,没有返回值:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <title>ES6 测试</title>
    <!-- JQuery CDN-->
    <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>

    <script type="module">
        $(function () {
            let map = new Map();
            map.set("name", "华安").set("age", 35);
            map.set(110, "公安局");

            console.log(map.size);//输出:3
            map.clear();
            console.log(map.size);//输出:0
        });
    </script>
</head>
<body>
</body>
</html>

Map 遍历

Map 结构原生提供三个遍历器生成函数和一个遍历方法, 需要特别注意的是,Map 的遍历顺序就是插入顺序。

• keys():返回键名的遍历器。

• values():返回键值的遍历器。

• entries():返回所有成员的遍历器。

• forEach():遍历 Map 的所有成员。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>增强 For 循环</title>
    <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
    <script type="text/javascript">
        let map = new Map([
            ["name", "赵子龙"],
            ["age", 35],
            ["address", "常山"]
        ]);

        console.log("--------1------");
        // 依次输出:name、age、address
        for (let keyLoop of map.keys()) {
            console.log(keyLoop);
        }

        console.log("--------2------");
        //依次输出:赵子龙、35、常山
        for (let valueLoop of map.values()) {
            console.log(valueLoop);
        }

        console.log("--------3------");
        //依次输出:name 赵子龙、age 35、address 常山
        /**其中循环的 item 相当于 Java 中 Map 迭代时的 Entry*/
        for (let item of map.entries()) {
            console.log(item[0], item[1]);
        }

        console.log("--------4------");
        //依次输出:name 赵子龙、age 35、address 常山
        /**上面可以简写如下*/
        for (let [keyLoop,valueLoop] of map.entries()) {
            console.log(keyLoop, valueLoop);
        }

        console.log("--------5------");
        //依次输出:name 赵子龙、age 35、address 常山
        /**上面可以再简写如下*/
        for (let [keyLoop,valueLoop] of map) {
            console.log(keyLoop, valueLoop);
        }

        //依次输出:name 赵子龙、age 35、address 常山
        console.log("--------6------");
        map.forEach(function (value, key) {
            console.log(key, value);
        })

    </script>
</head>
<body>
<div id="myDiv"></div>
</body>
</html>

猜你喜欢

转载自blog.csdn.net/wangmx1993328/article/details/84030831