10. Set - Map 数据结构
Set 的概念
* set 类似数组,集合中的元素不能重复
* map 类似对象,key值任意数据类型
{ let list = new Set(); //增加元素的方法 list.add(5); list.add(7); //获取长度 console.log(list.size); //2 }
Set 的转换
{ // 将数组转换为 Set 集合 let arr = [1, 2, 3, 4, 5]; let list = new Set(arr); console.log(list.size); //5 } { let list = new Set(); list.add(1); list.add(2); // 不生效 list.add(1); console.log(list); //Set(2) {1, 2} }
数组去重
{ //数组去重, 但不能过滤数据类型 let arr = [1, 3, 3, 4, 5, 7, 7, 7]; let list2 = new Set(arr); console.log(list2); //Set(5) {1, 3, 4, 5, 7} console.log([...list2]); //[1, 3, 4, 5, 7] }
常用API
{ //常用API let arr = ["add", "delete", "clear", "has"]; let list = new Set(arr); // 包含 console.log(list.has("add")); //true // 删除 console.log(list.delete("add"), list); //true , Set(3) {"delete", "clear", "has"} // 清空 list.clear(); console.log(list); //Set(0) {} }
遍历
let...of
let arr = ["add", "delete", "clear", "has"]; let list = new Set(arr); for (let key of list.keys()) { console.log("keys", key); // keys add // keys delete // keys clear // keys has }
for (let value of list.values()) { console.log("values", value); // values add // values delete // values clear // values has }
for (let value of list) { console.log("list", value); // list add // list delete // list clear // list has }
for (let [key, value] of list.entries()) { console.log("entris", key, value); // entris add add // entris delete delete // entris clear clear // entris has has }
forEach
list.forEach(item => { console.log(item); // add // delete // clear // has });
结论: Set 的 key 和 value 都是一样的,都是元素的名称
WeakSet
- 和 Set 支持的数据类型不一样, 元素只能是对象
-
对象都是弱引用,不是值拷贝,而是地址引用。不会和垃圾回收机制挂钩
-
没有clear 方法,没有size属性,不能遍历
{ let weakList = new WeakSet(); let arg = {}; weakList.add(arg); // weakList.add(2); //Invalid value used in weak set console.log(weakList); //WeakSet {{…}} console.log(weakList.size); //undefined }
Map
// 声明 { let map = new Map(); let arr = ["123"]; //添加元素用set, 获取用get map.set(arr, 456); console.log(map, map.get(arr)); //Map {["123"] => 456} 456 } { // 参数:内方括号代表一个元素,内部为 key value let map = new Map([["a", 123], ["b", 456]]); console.log(map); //Map(2) {"a" => 123, "b" => 456} }
常用属性方法,基本同Set
{ let map = new Map([["a", 123], ["b", 456]]); console.log(map.size); //2 console.log(map.delete("a"), map); //true Map(1) {"b" => 456} console.log(map.clear()); console.log(map); //Map(0) {} }
Map 的遍历和 Set 一模一样
WeakMap
- key 值 必须是对象
-
没有 size 不能使用 clear
-
不能遍历
{ let weakmap = new WeakMap(); let o = {}; weakmap.set(o, 123); console.log(weakmap, weakmap.get(o)); //WeakMap {{...} => 123} 123 }
map-set 与 数组和对象的比较
map 与数组
{ // 数据结构的横向对比 增、查、改、删 let map = new Map(); let array = []; //增 map.set("t", 1); array.push({ t: 1 }); console.info("map-array-add", map, array); //Map(1) {"t" => 1} //[{t:1}] //查 let map_exist = map.has("t"); //返回布尔值 let array_exist = array.find(item => item.t); //返回这个值 console.info("map-array", map_exist, array_exist); // true {t:1} //改 map.set("t", 2); array.forEach(item => (item.t ? (item.t = 2) : "")); console.info("map-array-modify", map, array); //Map(1) {"t" => 2} //[{t:2}] //删 map.delete("t"); let index = array.findIndex(item => item.t); array.splice(index, 1); console.info("map-array-empty", map, array); //Map(0) {} //[] }
set与数组
{ let set = new Set(); let array = []; //增 set.add({ t: 1 }); array.push({ t: 1 }); console.info("set-array", set, array); // Set(1) {{t:1}} // [{t:1}] //查 let set_exist = set.has({ t: 1 }); //因为是引用地址 let array_exist = array.find(item => item.t); //返回这个值 console.info("set-array", set_exist, array_exist); //false {t:1} //改 set.forEach(item => (item.t ? (item.t = 2) : "")); array.forEach(item => (item.t ? (item.t = 2) : "")); console.log("set-array-modify", set, array); // Set(1) {{t:2}} // [{t:2}] //删 set.forEach(item => (item.t ? set.delete(item) : "")); let index = array.findIndex(item => item.t); array.splice(index, 1); console.info("set-array-empty", set, array); //Set(0) {} //[] }
Map set 与 对象
{ //Map set 与 对象 let item = { t: 1 }; let map = new Map(); let set = new Set(); let obj = {}; //增 map.set("t", 1); set.add(item); obj["t"] = 1; console.log("map-set-obj", map, set, obj); // Map(1) {"t" => 1} Set(1) {{t:1}} {t: 1} //查 console.info({ map_exist: map.has("t"), set_exist: set.has(item), obj_exist: "t" in obj }); //{map_exist: true, set_exist: true, obj_exist: true} //改 map.set("t", 2); item.t = 2; //存储了数据,所以修改数据本身 obj["t"] = 2; console.log("map-set-obj-modify", map, set, obj); //Map(1) {"t" => 2} Set(1) {{t: 2}} {t: 2} //删 map.delete("t"); set.delete(item); delete obj["t"]; console.log("map-set-obj-empty", map, set, obj); //Map(0) {} Set(0) {} {} }
总结:
* 能使用Map 不使用 数组,有数据结果存储唯一性应考虑 Set
11. Proxy(代理) Reflect(反射)
- 连接用户和原始对象的层
-
为操作Object提供新的Api
-
二者方法是一样的
{ //供应商 也是原始对象 let obj = { time: "2018-07-08", name: "net", _r: 123 }; //代理商 Proxy对象 let monitor = new Proxy(obj, { //拦截对象属性的读取 get(target, key) { return target[key].replace("2018", "2019"); }, //拦截对象属性的设置 set(target, key, value) { if (key === "name") { return (target[key] = value); } else { return target[key]; } }, //拦截当前对象是否拥有某个属性 has(target, key) { if (key === "name") { return target[key]; } else { return false; } }, //拦截对象 删除属性 deleteProperty(target, key) { if (key.indexOf("_") > -1) { delete target[key]; return true; } else { return target[key]; } }, //拦截Object.keys, Object.getOwnPropertySymbols, Object.getOwnPropertyNames ownKeys(target) { //保护 time 属性 return Object.keys(target).filter(item => item != "time"); } }); //用户而言 是直接操作monitor对象 console.log("get", monitor.time); //2019-07-08 monitor.name = "qqq"; console.log("set", monitor.name, monitor); //qqq Proxy {time: "2018-07-08", name: "qqq", _r: 123} console.log("has", "name" in monitor, "time" in monitor); //true false // delete monitor.time; // console.log("delete", monitor); //Proxy {time: "2018-07-08", name: "qqq", _r: 123} // delete monitor._r; // console.log("delete", monitor); //Proxy {time: "2018-07-08", name: "qqq"} console.log("ownKeys", Object.keys(monitor)); // ["name", "_r"] }
Reflect 用法和 Proxy 一样
{ let obj = { time: "2018-07-08", name: "net", _r: 123 }; console.log("Reflect get", Reflect.get(obj, "time")); //2018-07-08 Reflect.set(obj, "name", "mukewang"); console.log(obj); //{time: "2018-07-08", name: "mukewang", _r: 123} console.log(Reflect.has(obj, "name")); //true } // 开发中的应用 { //实现校验模块 function validator(target, validator) { return new Proxy(target, { _validator: validator, set(target, key, value, proxy) { if (target.hasOwnProperty(key)) { let va = this._validator[key]; if (!!va(value)) { return Reflect.set(target, key, value); } else { throw Error(`不能设置${key}到${value}`); } } else { throw Error(`${key} 不存在`); } } }); } const personValidators = { name(val) { return typeof val === "string"; }, Age(val) { return typeof val === "number" && val > 18; } }; class Person { constructor(name, age) { this.name = name; this.age = age; return validator(this, personValidators); } } const person = new Person("lili", 30); console.log(person); //Proxy {name: "lili", age: 30} // person.name = 48; //报错 Uncaught Error: 不能设置name到48 person.name = "abc"; console.log(person); //Proxy {name: "abc", age: 30} }
12. CLASS 类
基本定义及生成实例
{ //基本定义及生成实例 class Parent { constructor(name = "muke") { this.name = name; } tell() { console.log("tell"); } } let v_parnet = new Parent("qqq"); console.log(v_parnet); //Parent {name: "qqq"} v_parnet.tell(); //tell }
继承
{ //继承 class Parent { constructor(name = "muke") { this.name = name; } } // 继承父类 class Child extends Parent {} console.log(new Child()); //Child {name: "muke"} } { //继承传递参数 class Parent { constructor(name = "muke") { this.name = name; } } // 子类向父类传递参数 class Child extends Parent { constructor(name = "child") { //调用super方法,得到子类的this对象 //super 指向父类,相当于 A.prototype.constructor.call(this) super(name); //定义自己的属性一定要放在super之后 this.type = "child"; } } console.log(new Child("hello")); //_Child {name: "hello", type: "child"} }
getter setter
{ //getter setter class Parent { constructor(name = "muke") { this.name = name; } //属性 不是函数 get longName() { return "mk" + this.name; } set longName(value) { this.name = value; } } let v = new Parent(); console.log("getter", v.longName); //mkmuke // 赋值就等于 set 操作 v.longName = "hello"; console.log("setter", v.longName); //mkhello }
静态方法 与 静态属性
{ // 静态方法 与 静态属性 class Parent { constructor(name = "muke") { this.name = name; } //静态方法是通过类去调用,而不是通过类的实例去调用 static tell() { console.log("tell"); } } // 直接定义静态属性 Parent.type = "test"; Parent.tell(); //tell console.log("静态属性", Parent.type); //test }
13. Promise-异步编程的解决方案
异步A执行完去执行B,传统方式:回调,事件触发
{ //ES5中回调 let ajax = function(callback) { console.log("执行"); setTimeout(() => { callback && callback.call(); }, 1000); }; ajax(function() { console.log("timeout1"); //执行 //timeout1 }); }
//ES6 Promise { let ajax = function() { console.log("执行2"); return new Promise(function(resolve, reject) { setTimeout(() => { resolve(); }, 1000); }); }; ajax().then(function() { console.log("timeout2"); //执行2 //timeout2 }); }
{ let ajax = function() { console.log("执行3"); return new Promise(function(resolve, reject) { setTimeout(() => { resolve(); }, 1000); }); }; ajax() .then(function() { return new Promise(function(resolve, reject) { setTimeout(() => { resolve(); }, 2000); }); }) .then(function() { console.log("timeout3"); }); }
捕获异常错误
{ let ajax = function(num) { console.log("执行4"); return new Promise(function(resolve, reject) { if (num > 5) { resolve(); } else { throw new Error("出错"); } }); }; ajax(6) .then(function() { console.log("log", 6); }) .catch(function(err) { console.log("catch", err); }); // ajax(3) // .then(function() { // console.log("log", 6); // }) // .catch(function(err) { // console.log("catch", err); // }); // catch Error: 出错 }
一些应用
{ //所有图片加载完成再添加到页面 function loadImg(src) { return new Promise(function(resolve, reject) { let img = document.createElement("img"); img.src = src; img.onload = function() { resolve(img); }; img.onerror = function(err) { reject(err); }; }); } function showImgs(imgs) { imgs.forEach(function(img) { document.body.appendChild(img); }); } // 把多个Promise实例当作一个实例 Promise.all([ loadImg( "http://img.mp.itc.cn/upload/20160415/43ba06629ee0493cb6784a7455cb5cc5.jpg" ), loadImg("http://img.duoziwang.com/2018/06/2018010154139925.jpg"), loadImg( "http://img.mp.itc.cn/upload/20160415/59cca1073eaa49788e349c67e4a9c37e.jpg" ) ]).then(showImgs); }
{ //有一个图片加载完成就添加到页面 function loadImg(src) { return new Promise(function(resolve, reject) { let img = document.createElement("img"); img.src = src; img.onload = function() { resolve(img); }; img.onerror = function(err) { reject(err); }; }); } function showImgs(img) { let p = document.createElement("p"); p.appendChild(img); document.body.appendChild(p); } //有一个状态改变,race实例也跟着改变 Promise.race([ loadImg( "http://img.mp.itc.cn/upload/20160415/43ba06629ee0493cb6784a7455cb5cc5.jpg" ), loadImg("http://img.duoziwang.com/2018/06/2018010154139925.jpg"), loadImg( "http://img.mp.itc.cn/upload/20160415/59cca1073eaa49788e349c67e4a9c37e.jpg" ) ]).then(showImgs); }