最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • javascript之Set&Map对象回顾

    正文概述 掘金(jayray)   2020-12-25   446

    ES6之前,数组一直是javascript中唯一的集合类型,而作为唯一的集合类型,数组使用的索引又是数值类型。因此,为使用非数值型索引的数据结构,ES6新增了Set集合和Map集合,两种新的集合类型。上一篇文章笔者已经回顾了数组对象及其方法,这篇文章依然是结合MDN的内容来回顾一下ES6中的Set和Map对象。

    1.Set集合

    ES6中新增的Set集合是一种有序列表,其中含有相互独立的非重复的值。MDN中Set的描述如下:Set对象是值的集合,你可以按照插入的顺序迭代它的元素,Set中的元素是唯一的。Set对象的构造函数为Set(),构造函数的属性有:

    • get Set[Symbol.species]:访问器属性,返回Set的构造函数,其被构造函数用以创建派生对象
    • protoType:表示构造函数的原型对象.

    所有Set对象的创建都是通过Set()构造函数来创建的。

    // 1.Set()构造函数创建,add()添加元素
    const set = new Set();
    set.add(1);
    set.add(2);
    set.add(3);
    console.log(set);   // Set(3) {1, 2, 3}
    
    // 2.一维数组
    const set1 = new Set([1,2,3,4,5]);
    console.log(set1);  // Set(5) {1, 2, 3, 4, 5}
    
    // 3.string字符串
    const text = 'Winter';
    const set2 = new Set(text);
    console.log(set2);  // Set(6) {'W', 'i', 'n', 't', 'e', 'r'}
    
    // 4.可迭代对象[Symbol.iterator]
    const obj = {
        [Symbol.iterator]: function* () {
            yield 1;
            yield 2;
            yield 3;
        }
    }
    const set2 = new Set(obj);
    console.log(set2);  // Set(3) {1, 2, 3}
    
    /* 应用场景 */
    // 1.Set转数组
    const set = new Set();
    set.add(1).add(2).add(3).add(4).add(5);
    const arr = [...set];
    console.log(arr);  // [1, 2, 3, 4, 5]
    
    // 2.数组去重
    const arr = [1,1,2,2,3,3,4,5];
    console.log([...new Set(arr)]);  // [1, 2, 3, 4, 5]
    

    所有Set实例都会继承Set.protoType,Set实例的属性有:

    • size:表示Set对象中的元素个数
    • constructor:表示创建该实例的构造函数

    Set对象实例的方法包括对象元素的操作方法和遍历方法。操作方法有:add(), delete(), clear(), has();遍历方法有:entries(), keys(), values(), forEach()。

    1.1 操作方法
    • add():向Set对象的末尾添加一个指定的值。

      语法:mySet.add(value)

    value必须,为添加到Set集合中的元素的值,元素的类型没有限制,但元素不能重复添加,NaN之间被视为相同的值,虽然NaN !== NaN。add()方法支持链式调用。

    // 支持链式调用,元素类型没有限制
    const mySet = new Set();
    mySet.add(1);
    mySet.add(2).add(true).add('hello').add(undefined).add(null).add({}).add(NaN);
    console.log(mySet);  // Set(8) {1, 2, true, "hello", undefined, null, {}, NaN}
    
    // NaN被视为相同的值,不会重复添加
    mySet.add(Number('hello'));
    console.log(mySet);  // Set(8) {1, 2, true, "hello", undefined, null, {}, NaN}
    
    • delete():从Set对象中删除指定的元素。

      语法:mySet.delete(value)

    value必需,为将要删除的元素。成功删除返回true,否则返回false。

    const mySet = new Set([1,2,3,4,5]);
    
    console.log(mySet.delete(3));  // true
    console.log(mySet.delete(6));  // false
    console.log(mySet);            // Set(4) {1, 2, 4, 5}
    
    • has():返回一个boolean值来指示对应的值value是否存在于Set对象中。

      语法:mySet.has(value)

    value必需,为测试是否存在于Set对象中的值。若value存在于Set中返回true,否则返回false。

    const set1 = new Set();
    set1.add(1).add(2).add(3).add(4).add(5);
    console.log(set1.has(3));        // true
    console.log(set1.has(6));        // false
    
    const set2 = new Set();
    const obj = {key: 1};
    set2.add(obj);
    console.log(set2.has(obj));      // true
    console.log(set2.has({key:1}));  // false,因为此时的{key:1}是另一个对象的引用
    set2.add({key:1});               // 现在set2中有两条不同引用的对象了
    console.log(set2);               // Set(2) {{key:1}, {key:1}}
    
    • clear():清空一个Set对象中的所有元素。返回值为undefined。

      语法:mySet.clear()

    const mySet = new Set();
    mySet.add(1).add(2).add(3).add(4).add(5);
    mySet.clear();
    
    console.log(mySet.size);    // 0
    console.log(mySet.has(3));  // false
    
    1.2 内置迭代器

    上一篇文章讲到,ES6中的3种类型的集合对象:数组、Set集合和Map集合,都内置了三种迭代器:entries(), values(), keys()。

    • entries():返回一个迭代器对象,对象的元素是类似[value,value]形式的数组,value是Set集合的每个元素,迭代器顺序即元素插入的顺序。

      语法:mySet.entries()

    返回值为一个新的包含[value,value]形式的数组迭代器元素。每次调用next()方法,都会返回一个结果对象,结果对象的value为一个数组,数组的两个元素都是Set集合对象的值。

    const mySet = new Set();
    mySet.add(1).add(2).add(3);
    
    const iter = mySet.entries();
    console.log(iter.next());  // {value: [1,1], done: false}
    console.log(iter.next());  // {value: [2,2], done: false}
    console.log(iter.next());  // {value: [3,3], done: false}
    console.log(iter.next());  // {value: undefined, done: true}
    
    • values():返回一个迭代器对象,对象的元素为集合的元素。

      语法:mySet.values()

    返回值为按照插入顺序返回的包含Set对象中的每个元素的迭代器对象。每次调用next()方法,返回的结果对象的value为Set集合对象的值。

    const mySet = new Set([1,2,3]);
    const iter = mySet.values();
    
    console.log(iter.next());  // {value: 1, done: false}
    console.log(iter.next());  // {value: 2, done: false}
    console.log(iter.next());  // {value: 3, done: false}
    console.log(iter.next());  // {value: undefined, done: true}
    
    • keys():返回和values()相同的迭代器对象,因为Set集合的键和值是相同的。

      语法:mySet.keys()

    const mySet = new Set([1,2,3]);
    const iter = mySet.keys();
    
    console.log(iter.next());  // {value: 1, done: false}
    console.log(iter.next());  // {value: 2, done: false}
    console.log(iter.next());  // {value: 3, done: false}
    console.log(iter.next());  // {value: undefined, done: true}
    

    Set集合的默认迭代器为values(),在for-of循环中,若没有显式指定迭代器则使用默认迭代器values()。

    1.3 遍历方法
    • forEach():根据集合中元素的插入顺序,依次遍历元素执行提供的回调函数。

      语法:mySet.forEach(callback(value,key,set),thisArg)

    其中,callback为遍历每个元素执行的回调函数,该函数接收三个参数:value为当前遍历的元素,key也表示当前遍历的元素,set为调用forEach的集合对象。thisArg为执行回调函数时的this对象。

    const mySet = new Set([1,2,3]);
    mySet.forEach((value,key) => {
      console.log(`mySet[${key}] = ${value}`);
    })
    
    // 'mySet[1] = 1'
    // 'mySet[2] = 2'
    // 'mySet[3] = 3'
    
    2.WeakSet集合

    我们知道,Set集合的元素类型不限。当我们将对象存储到Set的实例后,若Set实例中的引用存在,垃圾回收机制就不能释放该对象的内存空间,即使清除对象的原始引用,Set集合却保留了该对象的引用。(这里可以了解一下j s的垃圾回收机制:标记清除和引用计数。V8引擎采用的是分代式垃圾回收机制,年轻代采用复制清除算法,老年代采用标记清除算法。)

    const set = new Set();
    let obj = {name: 'zhang', age: 18};
    set.add(obj);
    
    console.log(set.size);   // 1
    
    // 移除对象的原始引用
    obj = null; 
    console.log(set.size);  // 1
    
    // 取回原始引用
    obj = [...set][0];
    console.log(obj);       // {name: 'zhang', age: 18}
    

    由此可见,Set集合存储对象可能会导致内存泄露的问题。为了解决这个问题,ES6引入了又一个类型:WeakSet集合(弱引用Set集合)。WeakSet集合只存储对象的弱引用,并且不可以存储原始类型的值,若集合中的弱引用式对象的唯一引用则会被回收并释放相应内存。

    WeakSet集合通过WeakSet()构造函数来创建,WeakSet对象实例没有size属性和clear()方法,只有constructor属性。集合支持3个方法:add()、has()和delete()。因为WeakSet实例的项是动态的,所以不能被遍历(没有遍历方法)。

    // WeakSet集合的创建
    const set = new WeakSet();
    let obj = {name: 'zhang', age: 18};
    
    // add()方法向集合中添加对象,只能添加对象,不能添加原始值
    set.add(obj);
    
    console.log(set.has(obj));  // true
    
    set.delete(obj);            
    
    console.log(set.has(obj));  // false
    

    Set与WeakSet最大的区别就是WeakSet保存的是对象的弱引用,且WeakSet只能保存对象,不能保存非对象值。

    3.Map集合

    Map对象保存键值对,并且能够记住键的原始插入顺序,任何值都可以作为一个键或一个值。Map对象在迭代时会根据对象中元素插入的顺序来进行。Map对象的构造函数为Map(),构造函数的属性有:

    • get Map[Symbol.species]:可访问属性,用以创建派生对象。
    • protoType:表示Map构造函数的原型。允许添加属性到原型上从而应用于所有的Map对象。

    Map对象的创建都是通过Map()构造函数来创建的。

    // 1.Map()构造函数创建,set()方法添加元素
    const map = new Map();
    map.set(1,'red');
    map.set(2, 'yellow');
    map.set(3, 'blue');
    console.log(map);  // Map(3) {1 => 'red', 2 => 'yellow', 3 => 'blue'}
    
    // 2.二维数组
    const map = new Map([[1, 'red'],[2, 'yellow'], [3, 'blue']]);
    console.log(map); // Map(3) {1 => 'red', 2 => 'yellow', 3 => 'blue'}
    

    Map对象实例都会继承Map.protoType,Map实例的属性有:

    • constructor:表示创建实例的构造函数
    • size:表示实例对象的键值对的数量

    Map对象实例的方法包括对象元素的操作方法和遍历方法。操作方法:set(), delete(), clear(), get(), has();遍历方法:entries(), keys(), values(), forEach()。

    3.1 操作方法
    • set():为Map对象添加更新一个指定键和值的键值对。若键已存在则更新键对应的值。

      语法:map.set(key, value)

    key为要添加或更新Map对象的元素的键,value为要添加或更新Map对象的元素的值。key和value的值支持所有类型。键名的等价性判断是通过Object,is()方法实现的。NaN被视为相同的键。

    const map = new Map();
    // 添加元素
    map.set(1, 'red');
    map.set('yellow',2);
    map.set(undefined,null);
    console.log(map);  // Map(3) {1 => "red", "yellow" => 2, undefined => null}
    
    // 更新元素
    map.set(1,'blue');
    map.set('yellow',3);
    map.set(undefined,undefined);
    console.log(map);  // Map(3) {1 => "blue", "yellow" => 3, undefined => undefined}
    
    • delete():移除Map对象中指定的元素

      语法:map.delete(key)

    key必须,为从Map对象中移除的元素的键。若Map对象中存在该元素,返回true;否则返回false。

    const map = new Map();
    map.set(1,'red');
    map.set(2,'yellow');
    map.set(3,'blue');
    
    console.log(map.delete(1));  // true
    console.log(map.delete(6));  // false
    console.log(map);            // Map(2) {2 => "yellow", 3 => "blue"}
    
    • get():获取Map对象中的指定键对应的元素。

      语法:map.get(key)

    key必须,为从目标Map对象中获取元素的键,返回值为Map对象中与指定键对应的值,若找不到该键则返回undefined。

    const map = new Map([[1,'red'],[2,'yellow'],[3,'blue']]);
    
    console.log(map.get(1));  // 'red'
    console.log(map.get(6));  // undefined
    
    • has():查找Map对象中是否存在指定元素,返回一个boolean值。

      语法:map.has(key)

    key必须,为检测是否存在指定元素的键值。若Map对象中存在则返回true,否则返回false。

    const map = new Map([['name','zhang'],['age',18],['sex','male']]);
    
    console.log(map.has('name'));   // true
    console.log(map.has('greet'));  // false
    
    • clear():移除Map对象中的所有元素。

      语法:map.clear()

    const map = new Map([['name','zhang'],['age',18],['sex','male']]);
    
    console.log(map.size);         // 3
    console.log(map.has('name'));  // true
    
    map.clear();
    
    console.log(map.size);         // 0
    console.log(map.has('name'));  // false
    
    3.2 内置迭代器

    Map集合对象同样内置了三种迭代器:entries(), values(), keys()。

    • entries():返回一个新的包含[key, value]对的迭代器对象,迭代顺序为Map对象的元素插入顺序。

      语法:map.entries()

    返回值为一个新的包含[key, value]形式的数组迭代器元素。每次调用next()方法,都会返回一个结果对象,结果对象的value为一个数组,数组的两个元素都是Map集合对象的键值对。

    const map = new Map([[1, 'red'], [2, 'yellow'], [3, 'blue']]);
    const iter = map.entries();
    
    console.log(iter.next());  // {value: [1, 'red'], done: false}
    console.log(iter.next());  // {value: [2, 'yellow'], done: false}
    console.log(iter.next());  // {value: [3, 'blue'], done: false}
    console.log(iter.next());  // {value: undifined, done: true}
    
    • values():返回一个迭代器对象,对象的元素为集合的元素的值。

      语法:map.values()

    返回值为按插入顺序返回的包含Map对象中的每个元素的值的迭代器对象。每次调用next()方法,返回的结果对象的value为Map集合对象的值。

    const map = new Map([[1, 'red'],[2, 'yellow'],[3, 'blue']]);
    const iter = map.values();
    
    console.log(iter.next());  // {value: 'red', done: false}
    console.log(iter.next());  // {value: 'yellow', done: false}
    console.log(iter.next());  // {value: 'blue', done: false}
    console.log(iter.next());  // {value: undifined, done: true}
    
    • keys():返回一个迭代器对象,对象的元素为集合的元素的键。

      语法:map.keys()

    返回值为按插入顺序返回的包含Map对象中的每个元素的键的迭代器对象。每次调用next()方法,返回的结果对象的value为Map集合对象的键。

    const map = new Map([[1, 'red'],[2, 'yellow'],[3, 'blue']]);
    const iter = map.keys();
    
    console.log(iter.next());  // {value: 1, done: false}
    console.log(iter.next());  // {value: 2, done: false}
    console.log(iter.next());  // {value: 3, done: false}
    console.log(iter.next());  // {value: undifined, done: true}
    

    Map集合的默认迭代器为entries(),在for-of循环中,若没有显式指定迭代器则使用默认迭代器entries()。

    3.3 遍历方法
    • forEach():按集合元素的插入顺序,遍历对象的每个元素执行指定的回调函数。

      语法:map.forEach(callback(value,key,map),thisArg)

    其中,callback为遍历每个元素执行的回调函数,该函数接收三个参数:value为当前遍历的元素,key也表示当前遍历的元素,map为调用forEach的集合对象。thisArg为执行回调函数时的this对象。

    const map = new Map([[1, 'red'],[2, 'yellow'],[3, 'blue']]);
    map.forEach((value,key) => {
      console.log(`map[${key}] = ${value}`);
    })
    
    // 'map[1] = red'
    // 'map[2] = yellow'
    // 'map[3] = blue'
    
    4.WeakMap集合

    WeakMap集合(弱引用的Map集合)同样是为了解决Map存储对象的强引用问题而设计出来的。WeakMap集合只存储对象的弱引用,并且键名不可以存储原始类型的值,若集合中的弱引用式对象的唯一引用则会被回收并释放相应内存。Map与WeakMap最大的区别就是WeakMap保存的是对象的弱引用,且WeakMap的键只能为对象,不能为非对象值。

    const map = new Map();
    let obj = {name: 'zhang', age: 18};
    map.set(obj, 1);
    
    console.log(map);   // Map(1) {{name: 'zhang', age: 18} => 1}
    
    // 移除对象的原始引用
    obj = null; 
    console.log(map);  // Map(1) {{name: 'zhang', age: 18} => 1}
    
    // 取回原始引用
    obj = map.keys().next().value;
    console.log(obj);       // {name: 'zhang', age: 18}
    

    WeakMap集合通过WeakMap()构造函数来创建,WeakMap对象实例没有size属性和clear()方法,只有constructor属性。集合支持4个方法:set()、get()、has()和delete()。因为WeakMap实例的项是动态的,所以不能被遍历(没有遍历方法)。

    const map = new Map();
    let obj = {name: 'zhang', age: 18};
    
    // set添加或更新元素,键必须是对象
    map.set(obj, 1);
    
    console.log(map.has(obj));  // true
    console.log(map.get(obj));  // 1
    
    map.delete(obj);            
    
    console.log(map.has(obj));  // false
    
    【参考文献】

    起源地下载网 » javascript之Set&Map对象回顾

    常见问题FAQ

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

    发表评论

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

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

    联系作者

    请选择支付方式

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