Set和Map

38 篇文章 0 订阅
25 篇文章 0 订阅
产生起因

JavaScript的默认对象表示方式{}可以视为其他语言中的MapDictionary的数据结构,即一组键值对。

但是JavaScript的对象有个小问题,就是键必须是字符串。但实际上Number或者其他数据类型作为键也是非常合理的。为了解决这个问题,最新的ES6规范引入了新的数据类型Mapset.

Set是一种叫做集合的数据结构,Map是一种叫做字典的数据结构

应用场景

数组去重和数据存储

Set (集合)[类数组]
  • 集合是由一组无序且唯一(即不能重复)的项组成的,可以想象成集合是一个既没有重复元素,也没有顺序概念的数组

    var a = new Set([1, 2, 3, {"1": "2"}, ["3","4"]])
    
  • ES6提供了新的数据结构Set。它类似于数组,但是成员的值都是唯一的,没有重复的值

  • Set 本身是一个构造函数,用来生成 Set 数据结构

    这里说的Set其实就是我们所要讲到的集合,先来看下基础用法

    const s = new Set();
    
    [2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));
    
    for (let i of s) {
      console.log(i);   // 2 3 5 4
    }
    
    // 去除数组的重复成员
    let array = [1,2,1,4,5,3];
    [...new Set(array)]     // [1, 2, 4, 5, 3]
    
    
方法和属性总结
  • 属性
    size: 返回set数据结构的数据长度

  • 操作方法

    1. add(value):添加某个值,返回 Set 结构本身。

    2. delete(value):删除某个值,返回一个布尔值,表示删除是否成功。

    3. has(value):返回一个布尔值,表示该值是否为 Set 的成员。

    4. clear():清除所有成员,无返回值。

      let set = new Set();
      console.log(set.add(1).add(2)); // Set [ 1, 2 ]
      
      console.log(set.delete(2)); // true
      console.log(set.has(2)); // false
      
      console.log(set.clear()); // undefined
      console.log(set.has(1)); // false
      console.log(set.size);  // 0
      
  • 遍历方法

    1. keys():返回键名的遍历器

    2. values():返回键值的遍历器

    3. entries():返回键值对的遍历器

    4. forEach():使用回调函数遍历每个成员,无返回值

      let set = new Set(['a', 'b', 'c']);
      console.log(set.keys()); // SetIterator {"a", "b", "c"}
      console.log([...set.keys()]); // ["a", "b", "c"]
      
      let set = new Set(['a', 'b', 'c']);
      console.log(set.values()); // SetIterator {"a", "b", "c"}
      console.log([...set.values()]); // ["a", "b", "c"]
      
      let set = new Set(['a', 'b', 'c']);
      console.log(set.entries()); // SetIterator {"a", "b", "c"}
      console.log([...set.entries()]); // [["a", "a"], ["b", "b"], ["c", "c"]]
      
      let set = new Set([1, 2, 3]);
      set.forEach((value, key) => console.log(key + ': ' + value));
      // 1: 1
      // 2: 2
      // 3: 3
      
方法剖析(实现原理)
  • 建一个集合

    function Set(arr = []) {    // 可以传入数组
        let items = {};
        this.size = 0;  // 记录集合中成员的数量
    }
    
    module.exports = Set;
    

    这里用{}对象来表示集合,也是因为对象不允许一个键指向两个不同的属性,保证了集合里的元素都是唯一的

  • has方法

    // has(val)方法
    this.has = function (val) {
      // 对象都有hasOwnProperty方法,判断是否拥有特定属性
      return items.hasOwnProperty(val);
    };
    
  • add方法

    // add(val)方法
    this.add = function (val) {
      if (!this.has(val)) {
        items[val] = val;
        this.size++; // 累加集合成员数量
        return true;
      }
      return false;
    };
    
    
  • keys、values方法

    // keys()方法
    this.keys = function () {
      return Object.keys(items); // 返回遍历集合的所有键名的数组
    };
    // values()方法
    this.values = function () {
      return Object.values(items); // 返回遍历集合的所有键值的数组
    };
    
  • forEach方法

    // forEach(fn, context)方法
    this.forEach = function(fn, context = this) {
        for (let i = 0; i < this.size; i++) {
            let item = Object.keys(items)[i];
            fn.call(context, item, item, items);    
        }
    };
    
  • Array.from()

    将Set类数组转化为真实的数组

    let arrayLike = {
        0: 'tom', 
        1: '65',
        2: '男',
        3: ['jane','john','Mary'],
        'length': 4
    }
    let arr = Array.from(arrayLike)
    console.log(arr) // ['tom','65','男',['jane','john','Mary']]
    
  • 与Array之间的关系

  • var myArray = ["value1", "value2", "value3"];
    
    // 用Set构造器将Array转换为Set
    var mySet = new Set(myArray);
    
    mySet.has("value1"); // returns true
    
    // 用...(展开操作符)操作符将Set转换为Array
    console.log([...mySet]); // 与myArray完全一致
    
  • 高级用法

    let set = new Set([2, 1, 3]);
    console.log(set.keys());    // [ '1', '2', '3' ]
    console.log(set.values());  // [ 1, 2, 3 ]
    console.log(set.size);      // 3
    set.delete(1);
    console.log(set.values());  // [ 2, 3 ]
    set.clear();
    console.log(set.size);      // 0
    
    // 并集
    let a = [1, 2, 3];
    let b = new Set([4, 3, 2]);
    let union = new Set(a).union(b).values();
    console.log(union);     // [ 1, 2, 3, 4 ]
    //或者
    let a  = new Set([1, 2, 3, 4])
    let b = new Set([4, 5, 6])
    let union = new Set([...a, ...b])
    console.log(union) //1 2 3 4 5 6 去掉重复的4
    
    
    // 交集
    let c = new Set([4, 3, 2]);
    let intersect = new Set([1,2,3]).intersect(c).values();
    console.log(intersect); // [ 2, 3 ]
    //或者
    let a = new Set([1, 2, 3, 4])
    let b = new([4, 5, 6])
    let difference = [...a].filter(function(ele) {
      return b.has(ele);
    }) // 4
    //箭头函数
    let difference = [...a].filter(x => x.has(x)) // 4
    
    // 差集
    let d = new Set([4, 3, 2]);
    let difference = new Set([1,2,3]).difference(d).values();
    // [1,2,3]和[4,3,2]的差集是1
    console.log(difference);    // [ 1 ]
    //或者
    let a = new Set([1, 2, 3, 4])
    let b = new([4, 5, 6])
    let difference = [...a].filter(function (ele) {
      return !b.has(ele);
    }) // 1, 2, 3
    
Map (字典)[类对象]

它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适;

那么集合又和字典有什么区别呢:

  • 共同点:集合、字典可以存储不重复的值

  • 不同点:集合是以[值,值]的形式存储元素,字典是以[键,值]的形式存储

    这里说的Set其实就是我们所要讲到的集合,先来看下基础用法

    const m = new Map();
    const o = {p: 'Hello World'};
    m.set(o, 'content')
    m.get(o) // "content"
    
    m.has(o) // true
    m.delete(o) // true
    m.has(o) // false
    
方法和属性总结
  • 属性

    size:返回字典所包含的元素个数

  • 操作方法

    1. set(key, val): 向字典中添加新元素

    2. get(key):通过键值查找特定的数值并返回

    3. has(key):如果键存在字典中返回true,否则false

    4. delete(key): 通过键值从字典中移除对应的数据

    5. clear():将这个字典中的所有元素删除

    6. let m = new Map();
      m.set('Jay', 'Jay的Chou');
      m.set(true, '真的');
      console.log(m.has('Chou')); // false
      console.log(m.size); // 2
      console.log(m.keys()); // [ 'Jay', 'true' ]
      console.log(m.values()); // [ 'Jay的Chou', '真的' ]
      console.log(m.get('jay')); // undefined
      
      m.delete(true);
      console.log(m.keys()); // [ 'Jay' ]
      console.log(m.values()); // [ 'Jay的Chou' ]
      

      由于一个key只能对应一个value,所以,多次对一个key放入value,后面的值会把前面的值冲掉:

      var m = new Map();
      m.set('Adam', 67);
      m.set('Adam', 88);
      m.get('Adam'); // 88
      

      Map方法接受一个二维数组当做参数

      var m = new Map([['name', 'zhangsan'],['sex', 'male']]);
      console.log(m); //Map {"name" => "zhangsan", "sex" => "male"}
      
  • 遍历方法

    1. keys():将字典中包含的所有键名以数组形式返回

    2. values():将字典中包含的所有数值以数组形式返回

    3. entries():返回键值对的遍历器

    4. forEach():遍历字典的所有成员

      var map = new Map([['age', 19],['height', 180]]);
      
      for (let key of map.keys()) {
        console.log(key); // age height
      }
      
      for (let value of map.values()) {
        console.log(value); //19 180
      }
      
      for (let item of map.entries()) {
        console.log(`${ item[0] }: ${ item[1] }`);  //age: 19  height: 180
      }
      
      for (let [key, value] of map.entries()) {
        console.log(`${ key }: ${ value }`); //age: 19  height: 180
      }
      
      for (let [key, value] of map) {
        console.log(`${ key }: ${ value }`); //age: 19  height: 180
      }
      
      map.forEach((value, key, map) => {
        console.log(`${ key }: ${ value }`); //age: 19  height: 180
      });
      
方法剖析(实现原理)
  • 建一个字典

    function Map() {
        let items = {};
    }
    
    module.exports = Map;   // 导出
    
  • has方法

    // has(key)方法
    this.has = function (val) {
      return items.hasOwnProperty(val);
    };
    
  • set和get方法

    // set(key, val)方法
    // set相同key时,后面声明的会覆盖前面
    // 如: new Map().set({}, 'a')
    this.set = function (key, val) {
      items[key] = val;
    };
    // get(key)方法
    this.get = function (key) {
      // 判断是否有key,如果有的话直接返回对应的值
      // 如果读取一个未知的键,则返回undefined
      return this.has(key) ? items[key] : undefined;
    };
    
  • keys、values方法

    // keys()方法
    this.keys = function () {
      return Object.keys(items); // 返回遍历集合的所有键名的数组
    };
    // values()方法
    this.values = function () {
      return Object.values(items); // 返回遍历集合的所有键值的数组
    };
    
    
  • forEach方法

    // forEach(fn, context)方法
    this.forEach = function(fn, context = this) {
        for (let i = 0; i < this.size; i++) {
            let item = Object.keys(items)[i];
            fn.call(context, element, sameElement, set);     
        }
    };
    
  • 与Array之间的关系

    //Map转数组
    const map = new Map();
    map.set('name' , 'hello').set({},'world');
    
    [...map] //[["name","hello"],[{},"world"]]
    [...map.value()] //[["hello","world"]
    
    //数组转Map
    const map = new Map([["name","hello"],[{},"world"]]);
    
    map // {"name" => "hello", Object {} => "world"}
    
  • 与对象之间的关系

    //Map转为对象的方法
    function strMapToObj(strMap) {
      let obj = Object.create(null);
      for (let [k,v] of strMap) {
        obj[k] = v;
      }
      return obj;
    }
    let myMap = new Map().set('name', 'Virgo').set('old', '18');
    console.log(strMapToObj(myMap));// { name: "Virgo", old: "18"}
    
    //对象转为Map的方法
    function objToStrMap(obj) {
      let strMap = new Map();
      for (let k of Object.keys(obj)) {
        strMap.set(k, obj[k]);
      }
      return strMap;
    }
    var a = {name: 'Virgo', old: '18'}
    console.log(objToStrMap(a))//Map(2){"name" => "Virgo", "old" => "18"}
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值