最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 真正的键值存储机制-Map

    正文概述 掘金(JaylenL)   2021-08-06   330

    ECMAScript 6 以前,在 JavaScript 中实现“键/值”式存储可以使用 Object 来方便高效地完成,也就是使用对象属性作为键,再使用属性来引用值。

    但这种实现并非没有问题,Object只能使用数值、字符串或符号作为键,因此在将对象作为键时,object会将对象强制转换成字符串形式(调用其toString),再将其作为键值,如object => [object Object],这使得使用不同对象来映射不同值成为不可能。

    MapES6 新增的一种新的集合类型,它是一种真正的键/值存储机制。Map 的大多数特性都可以通过 Object 类型实现,但二者之间还是存在一些细微的差异。具体实践中使用哪一个,还是值得细细甄别。

    基本API

    Map提供了一系列初始化、操作、遍历的方法来方便我们使用。

    初始化

    Map是一个构造函数,需要使用new来创建示例

    let map = new Map();//Map(0) {}
    

    如果想在创建的同时初始化实例,可以给 Map 构造函数传入一个可迭代对象,需要包含键/值对数组。可迭代对象中的每个键/值对都会按照迭代顺序插入到实例中:

    // 使用嵌套数组初始化映射
    const m1 = new Map([ 
     ["key1", "val1"], 
     ["key2", "val2"], 
     ["key3", "val3"] 
    ]); 
    
    >>> Map(3) {"key1" => "val1", "key2" => "val2", "key3" => "val3"}
    
    
    // 使用自定义迭代器初始化映射
    const m2 = new Map({ 
     [Symbol.iterator]: function*() { 
     yield ["key1", "val1"]; 
     yield ["key2", "val2"]; 
     yield ["key3", "val3"]; 
     } 
    });
    
    >>> Map(3) {"key1" => "val1", "key2" => "val2", "key3" => "val3"}
    

    操作

    Map 的五大操作方法:setgethasdeleteclear

    size

    map对象的一个内部属性,返回元素的数量,该属性是只读的,因此不能像数组通过修改此值来修改大小。用set 方法修改size返回undefined

    let myMap = new Map();
    myMap.set("a", "alpha");
    myMap.set("b", "beta");
    myMap.set("g", "gamma");
    
    myMap.size // 3
    

    set

    添加或更新一个指定了键(key)和值(value)的(新)键值对,并返回自身,因此可链式调用。

    let myMap = new Map();
    
    // 将一个新元素添加到 Map 对象
    myMap.set("bar", "foo");
    myMap.set(1, "foobar");
    
    // 在Map对象中更新某个元素的值
    myMap.set("bar", "baz");
    
    //链式调用
    myMap.set('bar', 'foo')
         .set(1, 'foobar')
         .set(2, 'baz');
    

    get

    返回 Map 中的指定元素。

    let myMap = new Map();
    myMap.set("bar", "foo");
    
    myMap.get("bar");  // 返回 "foo"
    myMap.get("baz");  // 返回 undefined
    

    has

    返回一个 bool 值,用来表明 map 中是否存在指定元素。

    let myMap = new Map();
    myMap.set("bar", "foo");
    
    myMap.has("bar");  // returns true
    myMap.has("baz");  // returns false
    

    delete

    移除 Map 对象中指定的元素。

    let myMap = new Map();
    myMap.set("bar", "foo");
    
    myMap.delete("bar"); // 返回 true。成功地移除元素
    myMap.has("bar");    // 返回 false。"bar" 元素将不再存在于 Map 实例中
    

    clear

    移除 Map 对象中的所有元素,返回值是undefined

    let myMap = new Map();
    myMap.set("bar", "baz");
    myMap.set(1, "foo");
    
    myMap.size;       // 2
    myMap.has("bar"); // true
    
    myMap.clear();
    
    myMap.size;       // 0
    myMap.has("bar")  // false
    

    遍历

    Map 提供了一些方法来返回迭代器对象,方便我们使用for...offorEach进行遍历

    keys

    返回一个引用的 Iterator 对象。它包含按照顺序插入 Map 对象中每个元素的 key 值。

    let myMap = new Map();
    myMap.set("0", "foo");
    myMap.set(1, "bar");
    myMap.set({}, "baz");
    
    let mapIter = myMap.keys();
    
    console.log(mapIter.next().value); // "0"
    console.log(mapIter.next().value); // 1
    console.log(mapIter.next().value); // Object
    
    for(let i of mapIter)
        console.log(i)
    

    values

    返回一个新的Iterator对象。它包含按顺序插入Map对象中每个元素的 value 值。

    let myMap = new Map();
    myMap.set("0", "foo");
    myMap.set(1, "bar");
    myMap.set({}, "baz");
    
    let mapIter = myMap.values();
    
    console.log(mapIter.next().value); // "foo"
    console.log(mapIter.next().value); // "bar"
    console.log(mapIter.next().value); // "baz"
    

    entires

    返回一个新的包含 [key, value] 对的 Iterator 对象,返回的迭代器的迭代顺序与 Map 对象的插入顺序相同。

    const m = new Map([ 
     ["key1", "val1"], 
     ["key2", "val2"], 
     ["key3", "val3"] 
    ]); 
    
    for (let pair of m.entries()) { 
     console.log(pair); 
    } 
    // [key1,val1] 
    // [key2,val2] 
    // [key3,val3]
    
    m.forEach((val, key) => console.log(`${key} -> ${val}`)); 
    // key1 -> val1 
    // key2 -> val2 
    // key3 -> val3
    

    与object的区别

    键的类型

    Map 的键可以是任意值,包括函数、对象或任意基本类型。 Object 的键只能是 String 或是 Symbol ,将除这2种类型外的类型作为键时,内部会将其转换成字符串再作为键。

    const div1 = document.getElementById('div1')
    const div2 = document.getElementById('div2')
    const obj = {}
    const map = new Map()
    
    
    // dom节点对象作为Object的键值时,会被转换成字符串(调用其toString),将值[object HTMLDivElement]作为键
    // 因此div1的值被div2覆盖了
    obj[div1] = 'div1'
    obj[div2] = 'div2'
    
    console.log(obj)//{ [object HTMLDivElement]: "div2" }
    
    // map直接将dom节点作为键
    map.set(div1,"div1")
    map.set(div2,"div2")
    
    console.log(map)//{ div#div1 => "div1", div#div2 => "div2" }
    

    键的顺序

    Map 中的 key 是有序的。因此,当迭代的时候,一个 Map 对象以插入的顺序返回键值。Object 的键是无序的

    []运算符

    MapObject都能使用[]运算符,但是效果不一样。

    const map = new Map()
    const obj = new Object()
    
    map['name']="jalenl" //Map(1){name:"Jalen"}
    map.has('name')//false
    map.get('name')//undefined
    
    map.set('name','jalenl')// Map(1){"name" => "Jalen"}
    map.has('name')//true
    
    obj['name']="jalenl" //{name:"Jalen"}
    

    MapObject使用[]修改的是自身的对象属性,但对于Map来说,自身的属性和元素没有任何关系,size()得到的元素数量不变。

    Map之所以能使用[]运算符,是因为其原型链最底层就是Object,它是从Object继承来的。

    const map = new Map()
    map instanceof Object//true
    

    自带的键

    Map 默认情况不包含任何键。只包含显式插入的键。一个 Object 实例有一个原型, 原型链上的键名有可能和自定义设置的键名产生冲突。

    迭代器

    Map内置迭代器对象,其默认迭代器是entries()Object没有内置迭代器。因此for...of可直接用于map实例,而object实例不可以,必须为object实例设置迭代器对象。

    const obj ={
      name:"jalenl",
      age: 18
    }
    const map = new Map([["name","jalenl"],["age","18"]])
    
    console.log(map[Symbol.iterator])//[Function: entries]
    console.log(obj[Symbol.iterator])//undefined
    

    如何选择

    对于普通开发任务来说,选择 ObjectMap 看个人偏好,但在内存管理和性能上,它俩有显著差别。

    1. 内存占用

    ObjectMap 的工程级实现在不同浏览器间存在明显差异,但存储单个键/值对所占用的内存数量 都会随键的数量线性增加。批量添加或删除键/值对则取决于各浏览器对该类型内存分配的工程实现。 不同浏览器的情况不同,但给定固定大小的内存,Map 大约可以比 Object 多存储 50%的键/值对。

    1. 插入性能

    ObjectMap 中插入新键/值对的消耗大致相当,不过插入 Map 在所有浏览器中一般会稍微快 一点儿。对这两个类型来说,插入速度并不会随着键/值对数量而线性增加。如果代码涉及大量插入操 作,那么显然 Map 的性能更佳。

    1. 查找速度

    与插入不同,从大型 ObjectMap 中查找键/值对的性能差异极小,但如果只包含少量键/值对, 则 Object 有时候速度更快。在把 Object 当成数组使用的情况下(比如使用连续整数作为属性),浏 览器引擎可以进行优化,在内存中使用更高效的布局。这对 Map 来说是不可能的。对这两个类型而言, 查找速度不会随着键/值对数量增加而线性增加。如果代码涉及大量查找操作,那么某些情况下可能选 择 Object 更好一些。

    1. 删除性能

    使用 delete 删除 Object 属性的性能一直以来饱受诟病,目前在很多浏览器中仍然如此。为此, 出现了一些伪删除对象属性的操作,包括把属性值设置为 undefinednull。但很多时候,这都是一 种讨厌的或不适宜的折中。而对大多数浏览器引擎来说,Mapdelete()操作都比插入和查找更快。 如果代码涉及大量删除操作,那么毫无疑问应该选择 Map


    起源地下载网 » 真正的键值存储机制-Map

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元