码迷,mamicode.com
首页 > 其他好文 > 详细

Set 和 Map 数据结构

时间:2017-10-18 00:11:18      阅读:240      评论:0      收藏:0      [点我收藏+]

标签:document   ini   垃圾   bool   back   foo   nts   它的   布尔   

Set

Set 对象允许你存储任何类型的 唯一值, 无论是 原始值(一共6种,string, number, boolean, undefined, null,和 es6 新增的 symbol) 还是 对象引用(Object)。

先用代码体会下这段概念的含义,直接在 Chrome 控制台创建一个 Set 数据类型,并因此向 Set 的实例中添加 原始值 和 对象引用,查看最终的 Set 数据机构和成员个数

技术分享

上图中,我们依次在 Set 数据结构中存储了5种常见的原始数据类型和2种Object数据类型,最终全部存储成功,并且查看到有7个成员

 

1、语法:

new Set([iterable]);

参数:iterable

可以传入一个 可迭代对象 用来初始化 Set 数据类型,它的所有元素将被添加到新的 Set 中。如果不指定此参数或者其值为 null,则新的Set 为空。

(可迭代对象包括:Array, String, Set, Map, TypedArray, 函数的 arguments 对象,NodeList 对象等)

返回值:

一个新的 Set 对象

 

我们现在依次在 Chrome 控制台中用 可迭代对象 和 普通原始数据类型(String 属于可迭代对象)来初始化 Set 数据类型

技术分享

再来看一个 NodeList 作为参数来初始化 Set 数据类型的小栗子:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div>11</div>
    <div>22</div>
    <div>33</div>
    <script>
        var divs = document.querySelectorAll(div);
        var set_NodeList = new Set(divs);
        console.log(set_NodeList);
    </script>
</body>
</html>

输出结果:

技术分享

2、概括:

(1)、Set 中的元素是唯一的

let arr=[1,2,3,1,‘2‘];
let list2=new Set(arr);

console.log(‘unique‘,list2);   // Set(4) {1, 2, 3, "2"}

 

(2)、向 Set 加入值的时候,不会发生类型转换,所以 5 和 "5" 是两个不同的值

let s6 = new Set();
s6.add(5);
s6.add(6);
s6.add(‘5‘);
s6.add(6);
console.log(s6);   // Set(3) {5, 6, "5"}

(3)、NaN, undefined 和 null 都可以被存储在 Set 中,在 Set 内部, 两个 NaN 是相等的(尽管在 es5 中 NaN != NaN)

技术分享

(4)、两个对象总是不相等的(包括空对象)

let s8 = new Set();
s8.add({});
s8.add({});
console.log(s8);   // Set(2) {Object {}, Object {}}

s8.add({‘name‘: ‘roger‘});
s8.add({‘age‘: 27});
console.log(s8);   // Set(4) {Object {}, Object {}, Object {name: "roger"}, Object {age: 27}}

(5)、数组去重   [ ...new Set( array ) ]

let arr1 = [‘apple‘, ‘huawei‘, ‘mi‘, ‘oppo‘, ‘apple‘];
let arr2 = [...new Set(arr1)];
console.log(arr2);   // ["apple", "huawei", "mi", "oppo"]

(6)、Array.from 方法可将 Set 结构转为数组

let s9 = new Set();
s9.add([1,2,3]);
let arr = Array.from(s9);
console.log(Array.isArray(arr));   // true

// 这就提供了去除数组重复成员的另一种方法
function dedupe(array) {
  return Array.from(new Set(array));
}
dedupe([1, 1, 2, 3]);   // [1, 2, 3]

 

3、遍历操作

Set 实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)

 

(1)、四个操作方法

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

delete(value):删除某个值,返回一个 bool 值,表示是否删除成功

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

has(value):返回一个 bool 值,表示该值是否是 Set 的成员

另外,size 相当于数组的 length 属性,表示 Set 成员的个数

let list = new Set ();
list.add(5);
list.add(7);
console.log(‘size‘,list.size);   // size 2

// 数组作为参数
let arr = [1,2,3,4,5];
let list1 = new Set (arr);
console.log(‘size‘,list1.size);   // size 5

// 数组去重
let list2 = new Set();
list2.add(2);
list2.add(3);
list2.add(3);
console.log(‘list2‘,list2);   // Set(2) {2, 3}

let arr3=[1,2,3,1,‘2‘];
let list3=new Set(arr3);
console.log(‘unique‘,list3);   // Set(4) {1, 2, 3, "2"}
let arr4 = [‘add‘, ‘delete‘, ‘has‘, ‘clear‘];
let list4 = new Set (arr4);

console.log(‘has‘, list4.has(‘add‘));   // has true

console.log(‘delete‘, list4.delete(‘add‘), list4);   // delete true Set(3) {"delete", "has", "clear"}

console.log(‘clear‘, list4.clear(), list4);   // clear undefined Set(0) {}

 

(2)、四个遍历方法

keys():返回键名

values():返回键值

entries():返回键值对

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

let arr7 = [‘one‘, ‘two‘, ‘three‘, ‘four‘, ‘five‘];
let list7 = new Set(arr7);

for (let key of list7.keys()){
    console.log(‘keys‘,key);
}

// keys one
// keys two
// keys three
// keys four
// keys five

for(let value of list7.values()){
    console.log(‘values‘,value);
}

// values one
// values two
// values three
// values four
// values five

for(let entries of list7.entries()){
    console.log(‘entries‘, entries)
}

entries (2) ["one", "one"]
entries (2) ["two", "two"]
entries (2) ["three", "three"]
entries (2) ["four", "four"]
entries (2) ["five", "five"]

list7.forEach(function(item){
    console.log(item)
})

// one
// two
// three
// four
// five

 

WeakSet

WeakSet 对象 与 Set 类似,也是不重复的值的集合

它与 Set 对象的区别有两点:

? WeakSet 的成员 只能是对象,不能是其它类型的值。而 Set 对象都可以;并且,WeakSet 没有 size 属性

技术分享

? WeakSet 中的对象都是弱引用,如果没有其它变量或属性引用这个对象值,那么这个对象值会被当垃圾回收掉。正因如此,WeakSet 对象是无法遍历的,没有办法拿到它所包含的元素

 

1、语法:

new WeakSet([iterable]);

参数:iterable

如果传入一个 可迭代对象, 则该对象所有的 迭代值 都会被自动添加进生成的 WeakSet 对象中

 

注意:初始化 WeakSet 的参数是有2个要求的

(1)、传入的参数必须是一个 可迭代对象

(2)、可迭代对象的值必须是 迭代值

通过一个例子来理解这段话:

技术分享

 

2、方法

WeakSet.prototype.add(value):向 WeakSet 实例添加一个新成员。
WeakSet.prototype.delete(value):清除 WeakSet 实例的指定成员。
WeakSet.prototype.has(value):返回一个布尔值,表示某个值是否在 WeakSet 实例之中。

技术分享

 

Map

Map 对象保存键值对。任何值(包括原始值和对象)都可以作为一个键或值

 

1、语法

new Map([iterable])

参数:iterable

与 WeakSet 类似,初始化Map时,Map 的参数必须是 iterable 对象,该对象的值也必须为 iterable值

技术分享

 

JavaScript 的对象,本质是键值对的集合(Hash 结构),但是传统上只能用字符串当键,这给它的使用带来了很大的限制。

例如,在《JavaScript高级程序设计》一书中,关于 Object 类型的介绍中,有这么一段话 “ 如果属性名中包含会导致语法错误的字符,或者属性名使用的是关键字或保留字,也可以使用方括号表示法。例如:”

person["first name"] = "Nicholas"; 

“ 由于 ‘first name’ 中包含一个空格,所以不能用点表示法来访问它。然而,属性名中是可以包含非字母非数字的,这时候就可以使用方括号表示法来访问它们。 ”

现在有一个如下结构的对象,该如何给这样一个对象添加和读取新成员呢?

{
        map:contra : {description: ‘Asynchronous flow control}, 
     map:dragula: {description: ‘
Drag and drop‘},
     map:woofmark: {description: ‘
Markdown and WYSIWYG editor‘} }

我们可以按照如下方法来实现:

   var obj = {}
    // 给对象添加成员
    function add(name, meta){
        obj[‘map:‘+name] = meta
    }
    // 读取对象成员
    function get(name){
        return obj[‘map:‘+name]
    }

    add(‘contra‘, { description: ‘Asynchronous flow control‘ })
    add(‘dragula‘, { description: ‘Drag and drop‘ })
    add(‘woofmark‘, { description: ‘Markdown and WYSIWYG editor‘ })
    
    get(‘contra‘)

但如果使用 Map 结构来实现的话,就可以简单很多

    var map = new Map()
    map.set(‘contra‘, { description: ‘Asynchronous flow control‘ })
    map.set(‘dragula‘, { description: ‘Drag and drop‘ })
    map.set(‘woofmark‘, { description: ‘Markdown and WYSIWYG editor‘ })
    console.log(map)

结果如下:

技术分享

通过前面的例子,我们来进一步了解下Map 和 Object 之间的相似点和不同点

相似点:

? 都是键值对的集合(Hash 结构)

? 允许按键 添加、删除一个值

? 可以删除键

? 可以检测一个键是否绑定了值

 

不同点:

? Object 的键只能是 字符串 或 Symbol,Map 的键可以是任意值

? 可以通过 size 属性获取 Map 的键值对个数,而 Object 的键值对个数只能手动确认

? Object 都有自己的原型 prototype,不过,从 ES5 开始,可以通过 “ map = Object.create( null ) ” 来创建一个没有原型的对象

 

2、Map 实例的属性和方法

1)、set(key, value)

set 方法设置键名 key 对应的键值 value,然后返回整个 Map 结构。如果 key 已经有值,则键值会被更新,否则就新生成该键

    const m = new Map();

    m.set(‘edition‘, 6)        // 键是字符串       Map(1) {"edition" => 6}
    m.set(262, ‘standard‘)     // 键是数值         Map(2) {"edition" => 6, 262 => "standard"}
    m.set(undefined, ‘nah‘)    // 键是 undefined   Map(3) {"edition" => 6, 262 => "standard", undefined => "nah"}

m.set([‘123‘], 456) // 键是数组 Map(4) {"edition" => 6, 262 => "standard", undefined => "nah", ["123"] => 456}
 

set 方法返回的是当前的 Map 对象,因此可以采用链式写法

let map = new Map()
      .set(1, ‘a‘)
      .set(2, ‘b‘)
      .set(3, ‘c‘);
// Map(3) {1 => "a", 2 => "b", 3 => "c"}

2)、get(key)

get 方法读取 key 对应的键值,如果找不到 key,返回 undefined

    const m = new Map();

    const hello = function() {console.log(‘hello‘);};
    m.set(hello, ‘Hello ES6!‘) // 键是函数

    m.get(hello)  // Hello ES6!
    m.get(‘world‘) // undefined

3)、size 属性

size 属性返回 Map 结构的成员总数

    const map = new Map()
    map.set(‘foo‘, true)
    map.set(‘bar‘, false)

    console.log(map.size)   // 2

(4)、has(key)

has 方法返回一个 bool 值,表示某个键是否在当前的 Map 对象中

const m = new Map();

m.set(‘edition‘, 6);
m.set(262, ‘standard‘);
m.set(undefined, ‘nah‘);

m.has(‘edition‘)     // true
m.has(‘years‘)       // false
m.has(262)           // true
m.has(undefined)     // true

(5)、delete(key)

delete 方法删除某个键,返回 true。如果删除失败,返回 false

const m = new Map();
m.set(undefined, ‘nah‘);
m.has(undefined)     // true

m.delete(undefined)
m.has(undefined)       // false

(6)、clear()

clear 方法清除所有成员,没有返回值

let map = new Map();
map.set(‘foo‘, true);
map.set(‘bar‘, false);

map.size // 2
map.clear()
map.size // 0

 

3、遍历方法

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

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

entries():返回所有成员的遍历器

forEach():返回Map的所有成员

技术分享

也可以使用 forEach() 方法遍历

var myMap = new Map();
myMap.set(0, ‘Zero‘);
myMap.set(1, ‘One‘);

myMap.forEach(function(value, key){
      console.log(key+‘=‘+value)
}, myMap)

// 0=Zero
// 1=One

 

4、与其它数据结构的互相转换

(1)、Map 转为数组,使用扩展运算符(...)

var map = new Map();
map.set({‘hello‘: ‘world‘})
       .set([1, NaN, ‘china‘]);

var map_array = [...map];
console.log(map_array);

// [[{hello: "world"},  undefined], [[1, NaN, "china"],  undefined]

 

(2)、数组转为Map,将数组传入Map构造函数

var map = new Map([[‘hello‘, null],[‘world‘, undefined]]);

// Map(2) {"hello" => null, "world" => undefined}

 

WeakMap

WeakMap 对象是一组键值对的集合,且其中的键是弱引用的。键必须是对象,值可以是任意值

 

1、语法

new WeakMap([iterable])

参数:iterable

iterable 是一个2元数组或者可遍历的且其元素是键值对的对象

var mp = new WeakMap();
mp.set({‘age‘: 27}, 2017);


//  WeakMap {{age: 27} => 2017}

mp.set(1,2);   // Uncaught TypeError: Invalid value used as weak map key

 

2、注意点:

(1)、WeakMap只接受对象作为键名(null除外),不接受其他类型的

(2)、WeakMap的键名所指向的对象,不计入垃圾回收机制

(3)、WeakMap 没有遍历操作,无法清空,也没有 size 属性

 

3、方法

WeakMap只有四个方法可用:get()、set()、has()、delete()

var wm1 = new WeakMap(),
    wm2 = new WeakMap(),
    wm3 = new WeakMap();
var o1 = {},
    o2 = function(){},
    o3 = window;

wm1.set(o1, 37);
wm1.set(o2, "azerty");
wm2.set(o1, o2); // value可以是任意值,包括一个对象
wm2.set(o3, undefined);
wm2.set(wm1, wm2); // 键和值可以是任意对象,甚至另外一个WeakMap对象
wm1.get(o2); // "azerty"
wm2.get(o2); // undefined,wm2中没有o2这个键
wm2.get(o3); // undefined,值就是undefined

wm1.has(o2); // true
wm2.has(o2); // false
wm2.has(o3); // true (即使值是undefined)

wm3.set(o1, 37);
wm3.get(o1); // 37
wm3.clear();
wm3.get(o1); // undefined,wm3已被清空
wm1.has(o1);   // true
wm1.delete(o1);
wm1.has(o1);   // false

 

Set 和 Map 数据结构

标签:document   ini   垃圾   bool   back   foo   nts   它的   布尔   

原文地址:http://www.cnblogs.com/rogerwu/p/7554427.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!