Set数据结构
1-1、ES6提供了新的数据结构—Set。它类似于数组,但是成员都是唯一的,没有重复;
Set本身是一个构造函数,用来生成Set数据结构。
const s = new Set();
[ 2, 2, 5, 4, 5, 2, 2 ].forEach( item => s.add( item ) );
for( let item of s ){
console.log( i ); // 2 5 4
};
1-2、Set函数可以接受一个数组(或者具有iterable接口的其他数据结构)作为参数,来初始化;
// 例1
const set = new Set( [ 1, 2, 3, 4 ] );
[ ...set ]; // [ 1, 2, 3, 4 ] 【接受数组为参数】
// 例2
const items = new Set([ 1, 2, 3, 4, 5, 5, 5]);
console.log( items.size ); // 5
// 例3
function getDivs(){
return [ ...document.querySelectorAll( 'div' ) ];
}
const set = new Set( getDivs() );
console.log( set.size ); // 10 【接受类似数组的对象作为参数】
1-3、Set加入值时不会发生类型转换,所以5和’5’是两个不同的值;Set内部判断两个值是 否相同类似于精确相等运算符(===),主要 的区别是【NaN等于自身】,精确相等运算符认为NaN不等于自身;
let set = new Set();
let a = NaN;
let b = NaN;
set.add( a );
set.add( b );
console.log( set ); // Set { NaN }
1-4、Set中两个对象是不相等;
let set = new Set();
let obj1 = {};
let obj2 = {};
set.add( obj1 );
set.add( obj2 );
console.log( set.size ); // 2
2-1、Set实例的属性和方法
Set.property.constructor: 构造函数,默认是Set函数;
Set.property.size: 返回Set实例的成员总数;
2-2、Set的操作方法
add(): 添加某个值,返回Set解构本身;
let set = new Set();
set.add( 1 ).add( 2 );
console.log( set.size ); // 2
delete():删除某个值,返回一个布尔值,表示删除是否成功;
let set = new Set();
set.add(1).delete(1); // true
has():返回一个布尔值,表示参数是否为Set成员;
let set = new Set();
set.add( 1 ).has( 1 ); // true
clear():清除所有成员;
let set = new Set();
set.add( 1 ).clear(); // {}
2-3、对比Object结构和Set结构的写法的不同之处;
// 对象的写法
const obj = { 'width': 10 };
if( obj[ someName ] ){ ...};
// Set的写法
const set = new Set();
set.add( 'widith' );
if( set.has( someName ) ){ ...};
2-4、Array.from()方法可以将Set解构转为数组;
const items = new Set( [ 1, 2, 3, 4, 5 ] );
const array = Array.from( items );
// 数组去重
let arr = [ 1, 2, 2, 1, 3, 3 ];
function dedupe( arr ){
return Array.from( new Set( arr ) );
};
dedupe( arr ); // [ 1, 2, 3 ]
2-5、Set结构的实例有4个遍历方法,可用于遍历成员;
keys()、values()、entries()返回的都是遍历对象,
由于Set结构没有键名,只有键值,所以keys()和values()行为完全一致;
【keys()】: 返回键名的遍历器
let set = new Set([1,2,3]);
for( let item in set.keys() ){
console.log( item ); // 1、2、3
};
【values()】: 返回键值的遍历器
let set = new Set([1,2,3]);
for( let item of set.values() ){
console.log( item ); // 1、2、3
};
【entries()】: 返回键值的遍历器,同时包括键名和键值
let set = new Set([1,2,3]);
for( let item in set.entries() ){
console.log( item ); // ["1","1"]、["2","2"]、["3","3"]
};
forEach(): 用于对每个成员执行某种操作,没有返回值; 第一个参数是处理函数;第二个参数表示绑定的this对象;
let set = new Set( [ 1, 2, 3 ] );
set.forEach( ( value, key ) => console.log( value * 2 ) ); // 2 4 6
2-6、遍历的应用 扩展运算符( …)内部使用 for…of循环,也可以用于Set结构;
let set = new Set( [ 'red', 'blue', 'pink' ] );
let arr = [ ...set ];
console.log( arr ); // [ 'red', 'blue', 'pink' ]
2-7、扩展运算符和Set结构相结合就可以去除数组的重复成员
let arr = [ 2, 2, 2, 3, 3, 3, 4, 4, 5, 5 ];
let cleatRepeat = [ ...new Set( arr ) ];
console.log( cleatRepeat );
2-8、遍历操作中同步改变原来的Set结构, 一种是利用原Set结构映射出一个新的结构,然后赋值给原来的Set结构;一种是利用Array.from()方法;
// 重新赋值
let set = new Set( [ 1, 2, 3 ] );
set = new Set( [ ...set ].map( val => val * 2 ) );
console.log( set ); // 2 4 6
// Array.from();
let set = new Set( [ 1, 2, 3 ] );
set = new Set( Array.from( set, val => val * 2 ) );
console.log( set ); // 2 4 6
Map数据结构
1-1、概述:Map数据结构。它类似于对象,也是键值对的集合,但是"键"的范围不限于字符串, 各种类型的值(包括对象)都可以当做键。也就是说,Object结构提供了"字符串-值"的对应 Map结构提供了"【值–值】"的对应,是一种更完善的Hash结构实现;
const map = new Map();
const obj = { p: 'hello' };
map.set( obj, 'content' );
console.log( map ); // key: {p: "1"} value: "content"
console.log( map.get( obj ) ); // 'content'
console.log( map.has( obj ) ); // true
console.log( map.delete( obj ) ); // true
console.log( map.has( obj ) ); // false
1-2、作为构造函数,Map也可以接受一个数组作为参数。该数组的成员是一个个表示键值的数组;不仅是数组,任何具有Iterator接口且每个成员都是一个双元素的数据结构都可以当做Map构造函数的参数。也就是,Set和Map都可以用来生成新的Map;
const map = new Map( [ [ 'name': zhang, 'title': 'hello' ] ] );
map.size; // 2
map.has( 'name' ); // true
map.get( 'name' ); // zhang
1-3、如果同一个键多次赋值,后面的值会覆盖前面的值
const map = new Map();
map.set( 1, 'a' ).set( 1, 'b' );
console.log( map.get( 1 ) ); // b
1-4、如果读取一个位置的键,则返回undefined
new Map().get( 'csdf' ); // undefined
1-5、只用对【同一个对象的引用】,Map结构才将其视为同一个键!!!
const map = new Map();
map.set(['a'],555);
map.get(['a']); // undefined 两个['a']内存地址不一样,取不到想要的值
1-6、Map的键实际上是和内存地址绑定的,只要内存地址不一样,就视为两个键 如果Map的键是一个简单类型的值(数值、字符串、布尔值),则只要两个值严格相等,Map就将其视为一个值,包括0和-0,另外,虽然NaN还不严格等于自身,但Map将其视为同一个键
let map = new Map();
map.set( -0, 123 );
map.get( +0 ); // 123
map.set( true, 1 );
map.set( 'true', 1 );
map.get( true ); // 1
map.set( undefined, 1 );
map.set( null, 2 );
map.get( undefined ); // 1
map.set( NaN,123 );
map.get( NaN ); // 123
2-1、Map属性
size属性: 返回Map结构的成员总数
const map = new Map();
map.set( 'foo', true ).set( 'bar', false );
console.log( map.size ); // 2
2-2、Map方法
set( key, value ):设置key所对应的键值,然后返回整个Map结构
get( key ): 获取key对应的键值,如果找不到key,则返回undefined
has( key ): 返回一个布尔值,表示某个键是否在Map数据结构中
delete( key ):删除某个键,返回true;如果删除失败,则返回false
clear(): 清除所有成员
2-3、遍历方法
keys(): 返回键名的遍历器
const map = new Map([['foo','no'],['bar','yes']]);
for( let key of map.keys() ){ console.log( key ) }; // "foo"、 "bar"
values(): 返回键值得遍历器
const map = new Map([['foo','no'],['bar','yes']]);
for( let key of map.values() ){ console.log( key ) }; // "no"、 "yes"
entries(): 返回所有成员的遍历器
const map = new Map([['foo','no'],['bar','yes']]);
for( let item of map.entries() ){ console.log( item[0], item[1] ) }; // "foo" "no" 、 "bar" "yes"
forEach(): 遍历Map的所有成员,与数组的forEach()方法类似,也可以实现遍历
此方法接受第二个参数,用于绑定this;
// this绑定
const reporter = {
report: function( key, value ){
cosole.log( key, value );
}
};
map.forEach( function( value, key, map ){
this.rep( key, value );
}, reporter );
2-4、Map转数组,使用扩展运算符
const myMap = new Map();
myMap.set( true, 7 ).set( { foo:3 },[ 'abc' ] ); // [[true,7],[{foo:3},['abc']]]
2-5、数组转Map,将数组传入Map构造函数可以转为Map
new Map( [ [ true, 7], [{a:'1'},'abc'] ] ); // true => 7 {a:'1'} => 'abc'
2-6、Map转对象,Map所有【键】都是字符串,则可以转为对象
function strMapToObj( arg ){
let obj = Object.create( null );
for( let [key,vlaue] of arg ){
obj[key] = value;
}
return obj;
};
const myMap = new Map().set('yes',true).set('no',false);
strMapToObj(myMap); // { yes: true, no: false }
2-7、对象转Map
function objToStrMap( obj ){
let strMap = new Map();
for( let key of obj.keys() ){
serMap.set( key, obj[ key ] );
}
};
const myMap = new Map().set('yes',true).set('no',false);
objToStrMap(myMap); // { yes: true, no: false }
2-8、Map转JSON分两种情况:一种是Map的键都是字符串; 一种是Map的键是非字符串,可以选择转为数组JSON
// 键都是字符串
function strMapToObject( map ){
let obj = Object.create( null );
for( let [ key, value ] of map ){
obj[ key ] = value;
}
return obj;
};
function strMapJson( map ){
return JSON.stringify( strMapToObject( map ) );
};
let myMap = new Map().set( 'yes', true ).set( 'no', false );
console.log( strMapJson( myMap ) ); // {"yes":true,"no":false}
// 转为数组JSON
function mapToArrayJson( map ){
return JSON.stringify( [ ...map ] );
};
let map = new Map().set( true, 7 ).set( {foo:3},['abc'] );
mapToArrayJson(map);
2-9、JSON转Map,分两种情况
// 键名都是字符串
function jsonToStrMap(jsonStr){
return objToStrMap( JSON.parse( jsonStr ) );
};
console.log(jsonToStrMap( '{ "yes": true, "no": false }'));
function objToStrMap( obj ){
let setMap = new Map();
for( let key of Object.keys( obj ) ){
setMap.set( key, obj[key] );
}
return setMap;
};
// JSON是数组
function jsonToMap( jsonstr ){
return new Map( JSON.parse( jsonstr ) );
};
jsonToMap( '[[true,7],[{foo:3},['abc']]]' )
// Map { true => 7, Object { foo: 3 } => [ 'abc' ] }
未完待续...