ES6解析*项目学习记录(三)

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);
}
原文地址:https://www.cnblogs.com/anqwjoe/p/11175003.html