es6 Set和WeakSet

2018-08-11 admin

Js大部分历史时期都只存在一种集合类型,也就是数组类型。数组在 JS 中的使用正如其他语言的数组一样,但缺少更多类型的集合导致数组也经常被当作队列与栈来使用。数组只使用了数值型的索引,而如果非数值型的索引是必要的,开发者便会使用非数组的对象。这种技巧引出了非数组对象的定制实现,即 Set 与 Map 。

Set:

Set概述

Set对象是值的集合,你可以按照插入的顺序迭代它的元素。 Set中的元素只会出现一次,即 Set 中的元素是唯一的。

 Set结构类似于数组,但是没有重复结构  Set会自动移除重复的值,因此可以用来过滤数组中的重复结构  Set内的对象是强引用

Set的构造:

a)    let set = new Set([1, 2, 3, 4]);

Set 构造器实际上可以接收任意可迭代对象作为参数。能使用数组是因为它们默认就是可迭代的,Set与Map也是一样,Set构造器会使用迭代器来提取参数中的值

b)    let set = new Set();

    set.add(1);
    set.add(2);
    set.add(2);
    //如果add对相同的值进行了多次调用,那么那么在第一次之后的调用实际上会被忽略
    set.add(3);
    set.add('3');

Set 不会使用强制类型转换来判断值是否重复。这意味着 Set 可以同时包含数值 3 与 字符串 “3” ,将它们都作为相对独立的项. Set判断是否重复使用了Object.is() 方法,唯一的例外是 +0 与 -0 在 Set 中被判断为是相等的

c) 还可以向Set添加多个值相同的对象,他们不会被合并为同一项。

let set = new Set();
let key1 = {};
let key2 = {};
set.add(key1);
set.add(key2);

Set的属性及方法:

1、属性

Set.prototype.constructor:构造函数,默认就是Set函数。
Set.prototype.size:返回Set实例的成员总数。

2、方法

Set的方法分为两类:操作方法 和 遍历方法

2.1、操作方法:

•add(value):添加某个值,返回 Set 结构本身。
  因为返回set本身,所以可以写成:
  set.add(1).add(2).add(3)

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

•has(value):返回一个布尔值,表示该值是否为Set的成员。
 set.has(2) ; // false

•clear():清除所有成员,没有返回值。

2.2、遍历方法:

forEach():使用回调函数遍历每个成员

es5给数组添加了forEach()方法,使得更容易处理数组中的每一项,没有返回值 对于数组来说forEach的三个参数: arr[].forEach(function(value,index,array){//do}) value数组中的当前项, index当前项的索引, array原始数组

但是对于Set来说:

  let set2 = new Set([{'a':1}, {'b':2}]);
    set2.forEach(function(value, key, ownerSet) {
      console.log(ownerSet === set2);
      console.log(value === key);
    });

key 与 value 总是相同的,同时 ownerSet 也始终等于 set 。此代码输出:
true
true
true
true

如果想在回调函数中使用当前的this,还可以在forEach中传入this作为第二个参数

let set = new Set([1, 2]);
let processor = {
    output(value) {
    console.log(value);
  },
  process(dataSet) {
    dataSet.forEach(function(value) {
      this.output(value);
    }, this);
  }
};
processor.process(set);

本例中,在processor.process方法中的set调用了forEach方法,并传递了this作为第二个参数,这样便能正确的调用到this.output()方法 或者也可以使用箭头函数来达到相同的效果,无需传入this,只需将上边的process改写成:

process(dataSet) {
  dataSet.forEach((value) => this.output(value));
}

keys()、values()和entries()

keys():返回键名的遍历器 values():返回键值的遍历器 entries():返回键值对的遍历器

keys方法、values方法、entries方法返回的都是遍历器对象,由于Set结构没有键名,只有键值(或者说键名和键值是同一个值),所以keys方法和values方法的行为完全一致。

let set = new Set(['red', 'green', 'blue']);

for (let item of set.keys()) {
  console.log(item);
}
// red
// green
// blue

for (let item of set.values()) {
  console.log(item);
}
// red
// green
// blue

for (let item of set.entries()) {
  console.log(item);
}
// ["red", "red"]
// ["green", "green"]
// ["blue", "blue"]

上面代码中,entries方法返回的遍历器,同时包括键名和键值,所以每次输出一个数组,它的两个成员完全相等。

Set 结构的实例默认可遍历,它的默认遍历器生成函数就是它的values方法。 Set.prototype[Symbol.iterator] === Set.prototype.values // true 这就意味着,可以省略values方法,直接用for…of循环遍历Set

let set = new Set(['red', 'green', 'blue']);

for (let x of set) {
  console.log(x);
}
// red
// green
// blue

Set常用场景

Set最经典的应用就是数组排重:

let set = new Set([1, 2, 3, 3, 3, 4, 5]),
array = [...set];
console.log(array);

Set与其他数据结构的互相转换

1、 Set与数组的转换

1.1、 Set转数组

使用扩展运算符可以很简单的将Set转成数组

let set = new Set([1, 2, 3, 3, 3, 4, 5]),
let array = [...set];
console.log(array); // [1,2,3,4,5]

该示例很好的说明了Set的一个重要的功能,数组排重,当然也很好的展示了,如何从Set转成数组的过程。 注意,这种转变是生成了一个新的数组对象原来的Set依然存在。

1.2、 数组转Set

如最初的构造示例:

let set = new Set([1,4,5,6,7]);

WeakSet:

由于 Set 类型存储对象引用的方式,它也可以被称为 Strong Set 。对象存储在 Set 的一个实例中时,实际上相当于把对象存储在变量中。只要对于 Set 实例的引用仍然存在,所存储的对象就无法被垃圾回收机制回收,从而无法释放内存。

当 JS 代码在网页中运行,同时你想保持与 DOM 元素的联系,在该元素可能被其他脚本移除的情况下,你应当不希望自己的代码保留对该 DOM 元素的最后一个引用(这种情况被称为内存泄漏) 为了缓解这个问题, ES6 也包含了 Weak Set ,该类型只允许存储对象弱引用,而不能存储基本类型的值。对象的弱引用在它自己成为该对象的唯一引用时,不会阻止垃圾回收。 WeakSet 里面的引用,都不计入垃圾回收机制,所以就不存在这个问题。因此,WeakSet 适合临时存放一组对象,以及存放跟对象绑定的信息。只要这些对象在外部消失,它在 WeakSet 里面的引用就会自动消失

WeakSet的构造:

Weak Set 使用 WeakSet 构造器来创建:

let set = new WeakSet(),
key = {};
// 将对象加入 set
set.add(key);
console.log(set.has(key)); // true
set.delete(key);
console.log(set.has(key)); // false

WeakSet的属性和方法:

基于WeakSet的弱引用特性,且里边的对象有可能随时消失的特性,es6规定WeakSet不可遍历,且没有size属性,WeakSet只有以下三个方法: WeakSet.prototype.add(value):向 WeakSet 实例添加一个新成员。 WeakSet.prototype.delete(value):清除 WeakSet 实例的指定成员。 WeakSet.prototype.has(value):返回一个布尔值,表示某个值是否在 WeakSet 实例之中。

WeakSet的特性

  1. 对于 WeakSet 的实例,若调用add()方法时传入了非对象的参数,就会抛出错误(has()或delete()则会在传入了非对象的参数时返回false);
  2. Weak Set 不可迭代,因此不能被用在 for-of 循环中;
  3. Weak Set 无法暴露出任何迭代器; (例如 keys()与values() 方法,因此没有任何编程手段可用于判断 Weak Set 的内容);
  4. Weak Set 没有 forEach() 方法;
  5. Weak Set 没有 size 属性。

WeakSet之所以不可遍历是由于 WeakSet 内部有多少个成员,取决于垃圾回收机制有没有运行,运行前后很可能成员个数是不一样的,而垃圾回收机制何时运行是不可预测的,因此 ES6 规定 WeakSet 不可遍历。 WeakSet常用场景 Weak Set 看起来功能有限,而这对于正确管理内存而言是必要的。一般来说,若只想追踪对象的引用,应当使用 Weak Set 而不是正规 Set

原文链接:https://segmentfault.com/a/1190000015962317

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处。

转载请注明:文章转载自 JavaScript中文网 [https://www.javascriptcn.com]

本文地址:https://www.javascriptcn.com/read-37705.html

文章标题:es6 Set和WeakSet

相关文章
2015 Web 2.0和AJAX如何做好优化
2015如何让做好web2.0和ajax的优化?JavaScript中文网总结当下提出以下四大优化意见,旨在帮助W前端开发人员有效利用APM解决上述问题。 随着Web应用程序速度与效率快速增长,网站已经成为企业与其客户进行交互的第一途径——...
2015-11-12
2015年将会有大量基于HTML5和JS的WEB应用
随着HTML5的定稿,以及JS的迅速发展,我们有理由相信,在接下来的一年里,将会涌现出大量的WEB应用,网站的表现形式将不再仅仅局限于过去的形式,必将在2015年引来一次重大改革! ...
2015-11-12
2015年2月国内操作系统市场份额概况,xp占46.29%,
规则调整:2012年6月1日开始,Mac操作系统中不再包含ipad、iphone市场份额。 ...
2015-11-12
Node.js v0.11.16 开发版发布
Node.js v0.11.16 开发版发布了,改进记录包括: openssl: Upgrade to 1.0.1l npm: Upgrade to 2.3.0 url: revert support of path for url.fo...
2015-11-12
JavaScript和Java
JavaScript和Java在某些方面相似但完全不同。 JavaScript语言类似于Java但是没有Java的静态类型和强类型检查,不过它们的语法和 C 语言都很相似。 JavaScript基于原型的对象模型,而不是更常见的基于类的对象...
2015-11-12
JavaScript基本语法和规范
JavaScript是区分大小写的,使用Unicode字符集。 在JavaScript中,语句以“;”结尾。 JavaScript脚本的源文本被从左到右执行。 虽然有时“;”是不必要的,但我们建议总是在你的语句结束处添加分号;它将避免副作用...
2015-11-12
jquery拼接ajax 的json和字符串拼接的方法
整理文档,搜刮出一个jquery拼接ajax 的json和字符串拼接的代码,稍微整理精简一下做下分享。 jQuery拼接字符串ajax <form id="myForm" action="#"&...
2017-04-01
数据类型和结构
ECMAScript标准定义了七种数据类型 1)布尔值(true 和 false) 2)null,一个特殊的关键字表示空,要注意,javascrip是区分大小写的,所以Null和null是不一样的 3)undefined 表示未定义 4)N...
2015-11-12
express不是内部或外部命令
最新express4.0版本中将命令工具分家出来了(项目地址:https://github.com/expressjs/generator) 安装一个命令工具,命令如下: npm install -g express-generator ...
2015-11-12
梳理前端开发使用eslint-prettier检查和格式化代码
问题痛点 在团队的项目开发过程中,代码维护所占的时间比重往往大于新功能的开发。因此编写符合团队编码规范的代码是至关重要的,这样做不仅可以很大程度地避免基本语法错误,也保证了代码的可读性。 对于代码版本管理系统(svn 和 git或者其他)...
2018-05-07
回到顶部