ES6学习笔记--Set和Map

Set

Set类似于数组,但是没有重复的值,成员是唯一的。
Set实例有两个属性:Set.prototype.constructor指向Set本身,Set.prototype.size返回Set实例的成员总数。
Set实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员):

Set的4个操作方法

  • add(value):添加某个值,返回Set结构本身。因此可以链式添加。
  • delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
  • has(value):返回一个布尔值,表示该值是否为Set的成员。
  • clear():清除所有成员,没有返回值。

Array.from方法可以将Set结构转为数值。

var set = new Set([1,2,3,4,5,4,3,2,1]);
var arr = Array.from(set);

//因此可以这样对数组去重
function dedupe(arr){
    return Array.from(new Set(arr));
};
dedupe([1,1,1,2,2,2]); // [1,2]

//另一种更简洁的数组去重方法:[...new Set(arr)]
[...new Set([111,222,111,222])]; // [111,222]

向Set加入值的时候,不会发生类型转换,所以5跟'5'是不同的值。
Set内部判断两个值是否相同,使用的算法叫'Same-value equality',它类似于全等=,区别是NaN ! NaN,但是在Set内部,NaN是等于自身的。

var set = new Set();
set.add('5').add(NaN).add(5).add(NaN);
set.size;//3
set;//{'5',NaN,5}

Set的四个遍历方法

  • keys():返回键名的遍历器
  • values():返回键值的遍历器
  • entries():返回键值对的遍历器
  • forEach():使用回调函数遍历每个成员
    Set遍历顺序就是插入顺序,使用Set保存一个回调函数列表,调用时就能保证按顺序调用。
    keys(),values(),entries()方法返回的都是遍历器对象(Iterator).由于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']

Set结构的实例默认可遍历,它的默认遍历器生成函数就是它的values方法,因此可以省略values方法,直接用for...of循环遍历Set.

let set = new Set(['red','green','blue']);
for(let item of set){
    console.log(x)
};
//red
//green
//blue

Set结构的实例forEach方法,用于对每个成员执行某种操作,没有返回值

let set = new Set([1,2,3]);
set.forEach((value,key) => console.log(value * 2));
//2,4,6

使用扩展运算符可以将数组的map和filter方法用于Set

let set = new Set([1,2,3]);
set = new Set([...set].map(x => x * 2));
set = new Set([...set].filter(x => (x % 2) == 0)

因此可以使用Set可以很容易实现并集,交集和差集

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

//并集
let union = new Set([...a,...b]);

//交集
let intersect = new Set([...a].filter(x => b.has(x)));

//差集
let difference = new Set([...a].filter(x => !b.has(x)));

Map

JS的对象,Object,是键值对的集合(Hash结构),但是只能使用字符串当作键。

var data = {},body = document.querySelector('body');
data[body] = 'bodyEle';
data['[object HTMLBodyElement]']; // 'bodyEle' //DOM节点作为data的键值被自动转为字符串

为了解决类似这种的问题,ES6提供了Map数据结构。Object是‘字符串--值’的对应,Map是‘值--值’的对应,是一种更完善的Hash结构

var m = new Map(),
    o = {p: 'Hello World'};
m.set(o,'content');
m.get(o); // 'content'
m.has(o); // true
m.size; // 1
m.delete(o);// true
m.has(o); // false
m.size; // 0
var m = new Map([
    [true,'foo'],
    ['true','bar']
]);
m.get(true); // 'foo'
m.get('true'); // 'bar' // true跟'true'是两个不同的值

m.set(0,false).set(0,'false');
m.get(0); // 'false' // 对同一个键多次赋值,后面的会覆盖前面的

m.get(1); // undefined // 读取一个未知的键,返回undefined

对于引用类型的键值,要特别小心

var map = new Map();
map.set(['a'],666);
map.get(['a']); // undefined // ['a'] != ['a']

var k1 = ['b'], k2 = ['b']; // k1 != k2
map.set(k1,111).set(k2,222);
map.get(k1); // 111
map.get(k2); // 222

对于基本类型的值,只要两个值全等,Map将其视为一个键,包括0和-0。另外,在Map里,NaN等于自身

let map = new Map();
map.set(NaN,123);
map.get(NaN); // 123
map.set(0,456);
map.get(-0); // 456

Map结构有以下属性和操作方法:

  • size属性,返回Map结构的成员总数
  • set(key,value),添加一个键值对,如果key已经存在,则覆盖其value值,返回整个Map结构,因此可以链式添加
  • get(key),读取key对应的value,如果key不存在,返回undefined
  • has(key),是否存在某个key值,返回true或false
  • delete(key),删除某个key,返回true.如果删除失败返回false
    -clear() 清除所有成员,没有返回值

Map原生提供三个遍历器生成函数和一个遍历方法

  • keys(),返回键名的遍历器
  • value(),返回键值的遍历器
  • entries(),返回所有成员的遍历器
  • forEach(),返回Map的所有成员
let map = new Map([
    [0,false],
    [1,true]
]);
for(let key of map.keys()){
    console.log(key)
}
for(let val of map.values()){
 console.log(val)
}

for(let item of map.entries()){
    console.log(item[0],item[1])
}
for(let [key,val] of map.entries()){
    console.log(key,val)
}
for(let [key,val] of map.entries()){
    console.log(key,val)
}

Map转化为数组,比较快速的方法是使用扩展运算符(...)

let map = new Map([
    [1,'one'],
    [2,'two'],
    [3,'three']
]);
[...map.keys()]; // [1,2,3]
[...map.values()];// ['one','two','three']
[...map.entries()];// [[1,'one'], [2, 'two'], [3, 'three']]
[...map]; // [[1,'one'], [2, 'two'], [3, 'three']]

//数组转化为Map直接将数组传入Map的构造函数
new Map([[1,'one'],[2,'two']]);

Map本身没有filter,map方法,可以使用数组来实现

let map0 = new Map()
    .set(1,'a')
    .set(2,'b')
    .set(3,'c');
let map1 = new Map(
    [...map0].filter(([key,val]) => key < 3)
);
let map2 = new Map(
    [...map0].map(([key,val]) => [key*2,val+'a'])
)

Map的forEach方法,与数组的forEach方法类似,可以实现遍历

map.forEach(function(val,key,map){ // 第二个参数可选,用来绑定this
    //...
},window)

Map与对象互转

//如果所有Map的键都是字符串,则可以转为对象
function mapToObj(strMap){
    let obj = {};
    for(let [key,val] of strMap){
        obj[key] = val;
    };
    return obj;
}
let myMap = new Map().set('yes', true).set('no', false);
mapToObj(myMap);
// { yes: true, no: false }

//对象转Map
function objToMap(obj){
    let map = new Map();
    for(let i of Object.keys(obj)){
        map.set(i,obj[i]);
    }
    return map;
}
objToMap({yes: true, no: false});
// [ [ 'yes', true ], [ 'no', false ] ]
posted @ 2017-03-09 22:27  艾泽拉斯回忆录  阅读(171)  评论(0编辑  收藏  举报