Object和Map的区别

Object是最常用的引用类型数据,可用于存键值对的集合,在ECMAScript 第一个版本里添加的

Map是专属键值对的集合,采用Hash结构存储,在ECMAScript 2015(Es6)中添加的

共同点: 键值对的动态集合,支持增加和删除键值对

不同点:

  1. 键的类型
    /**
     * 1. 键的类型
     * Object 
     *  - 键值必须是String或者Symbol,否则会进行数据类型的转换 
     * Map
     *  - 键可以是任意类型,包括对象、数组、函数等,不会进行类型转换,在添加键值对时,会通过严格相等(===)来判断属性是否已经存在
     */
    const obj = {a: 1}
    const arr = [1, 2]
    obj[arr] = 'arr' 
    console.log(obj)  // {a: 1, 1,2: 'arr'}
    
    const map = new Map()
    map.set('a', 1)
    map.set(2, 2)
    map.set(arr, 'arr')
    console.log(map)  //{'a' => 1, 2 => 2, Array(2) => 'arr'}
    // 特例
    // NaN === NaN  ==> false
    const map2 = new Map()
    map2.set(NaN, 1)
    map2.set(NaN, 2)
    console.log(map2)  // {NaN => 2}
  2. 键的顺序

    /**
     * 2. 键的顺序
     * Object
     * - key是无序的,不会按照添加的顺序返回
     *   - 1.对于大于0的整数,会按照大小进行排序;对于小数和负数会当字符串处理
     *   - 2.对于String类型,按照定义的书序输出
     *   - 3.对于Symbol类型,会直接过滤掉,不进行输出
     *     - 如果想输出Symbol类型,通过Object.getOwnPropertySymbols()方法
     * 
     * Map
     * - key是有序的,按照插入的顺序进行返回
     */
    
     const obj2 = {
       2: 2,
       '1': 1,
       'b': 'b',
       1.1: 1.1,
       0: 0,
       'a': 'a',
       [Symbol('s1')]: 's1',
       [Symbol('s2')]: 's2'
     }
    
     console.log(obj2) // {0: 0, 1: 1, 2: 2, b: 'b', 1.1: 1.1, a: 'a', Symbol(s1): 's1', Symbol(s2): 's2'}
     console.log(Object.keys(obj2)) // ['0', '1', '2', 'b', '1.1', 'a']
    
     const map3 = new Map()
     map3.set(2, 1)
     map3.set('1', 1)
     map3.set('b', 'b')
     map3.set(0, 0)
     map3.set('a', 'a')
     map3.set(Symbol('s1'), 's1')
     console.log(map3.keys()) // {2, '1', 'b', 0, 'a', Symbol(s1)}
  3. 键值对size

     /**
      * 3. 键值对size
      * Object
      *  - 只能手动计算,通过Object.keys()方法,或者通过for...in 循环统计
      * 
      * Map
      *  - 直接通过size属性访问
      * 
       */
    
       const obj3 = {
         'q': 1,
         'w': 2,
         'e': 3
       }
       console.log(Object.keys(obj3).length) // 3
    
       const map4 = new Map()
       map4.set('q', 1)
       map4.set('w', 2)
       map4.set('e', 3)
       console.log(map4.size) // 3
  4. 键值对的访问

       /**
        * 4. 键值对的访问
        * Object
        *  - 判断属性是否存在(undefined)
        * 
        * Map
        *  - 判断属性是否存在(has)
        */
    
        const obj4 = {
          name: 'Bulala',
          age: 18
        }
        console.log(obj4.name === undefined) // false
    
        const map5 = new Map()
        console.log(map5.has('name')) // false
  5. 迭代器(for...of)

        /**
         * 5. 迭代器(for... of)
         * Object
         *  - Object本身是不具备Iterator特性的,不能使用for.. if进行遍历
         * 
         * Map
         *  - Map结构的keys(), values(), entries()方法返回值都具有Iterator特性, 可以使用for.. if进行遍历
         */
        const obj5 = {
          name: 'Bulala',
          age: 18
        }
        // for(let key of obj5) {
        //   console.log(key) // 报错:Uncaught TypeError: obj5 is not iterable
        // }
    
        const map6 = new Map([
          ['name', 'Bulala'],
          ['age', 18]
        ])
        for(let key of map6.entries()) {
          console.log(key) // ['name', 'Bulala'] ['age', 18]
        }
  6. JSON序列化

        /**
         * 6. JSON序列化
         * Object
         *  - Object类型可以通过JSON.stringify()进行序列化操作
         * 
         * Map
         *  - Map结构不能直接进行序列化
         */
    
        const obj6 = {
          name: 'Bulala',
          age: 18
        }
        console.log(JSON.stringify(obj6)) // {"name":"Bulala","age":18}
        const map7 = new Map([
          ['name', 'Bulala'],
          ['age', 18]
        ])
        console.log(JSON.stringify(map7)) // {} 
        // 不能直接序列化,得先转成数值,在进行序列化
        console.log(JSON.stringify(Array.from(map7))) // [["name","Bulala"],["age",18]]

    总结:

    类型 适用场景
    Object

    1. 仅做数据存储,并且属性值仅为字符串或Symbol

    2. 需要进行序列化转换为JSON时

    3. 当做一个对象的实例,需要保留自己的属性和方法时

    Map

    1. 频繁更新和删除键值对时

    2. 存储大量数据时,尤其是key类型未知的情况下

    3. 需要频繁进行迭代处理

    若有不足之处望大家指教,后续其他内容会继续补充。

猜你喜欢

转载自blog.csdn.net/Star_ZXT/article/details/125020164