ES6语法

作者: lincimy | 来源:发表于2017-12-27 16:06 被阅读0次

    作用域的概念

    • es2015

      • 函数作用域
      • 全局作用域
    • es6

      • 函数作用域
      • 全局作用域
      • 块作用域(新增,标识:有大括号包围的)

      Ps:
      1.es6中强制开启了严格模式;
      2.let声明的变量只在块作用域中有效,let不能重复声明同一个变量;
      3.const声明变量初始化后不能修改常用类型变量值,但可以修改引用类型变量值(因为引用类型变量实际上是指针不变);

    解构赋值

    数组赋值

    例子:

    {
        let a,b,rest;
        [a,b] = [1,2];
        console.log(a,b);
    }
    
    

    结果输出:1 2

    {
        let a,b,rest;
        [a,b,...rest] = [1,2,3,4,5,6];
        console.log(a,b,rest);
        console.log(a,b,rest);
    }
    

    结果输出:1 2 [3, 4, 5, 6]

    对象赋值

    例子:

    {
        let a,b;
        ({a,b} = {a:2,b:4});
        console.log(a,b);
    }
    
    

    结果输出:2 4

    解构赋值默认值

    1.没有设置默认值的变量值为undefined

    2.默认值设值例子:

    {
        let a,b,c,rest;
        [a,b,c=3] = [1,2];
        console.log(a,b,c);
    }
    

    结果输出:1 2 3

    解构赋值作用

    1.变量交换

    {
        let a = 1;
        let b = 2;
        [a,b] = [b,a];
        console.log(a,b);
    }
    

    2.函数返回数组变量,可选择性的获取某个或某几个数值

    {
        function fn(){
            return [1,2,3,4,5];
        }
        let a,b;
        [a,,,b] = fn();
        console.log(a,b);
    }
    

    输出结果:1 4

    3.函数返回数组变量,只获取数组首个值,其他获取剩余数组

    {
        function fn(){
            return [1,2,3,4,5];
        }
        let a,b;
        [a,...b] = fn();
        console.log(a,b);
    }
    

    输出结果:1 [2,3,4,5]

    4.对象变量的赋值方法写法

    {
        let {a=1,b=5} = {a:3};
        console.log(a,b);
    }
    

    输出结果:3 5

    假设获取后台接口数据,取其中个别数据:

    {
        let metaData = {
           title: 'test',
           test: [{
               title: 'hello',
               description: 'helloworld'
           }] 
        };
        let {title:esTitle,test:[{title:cnTitle}]} = metaData;
        console.log(esTitle,cnTitle);
    }
    

    输出结果:test hello

    关于字符串拓展

    unicode字符处理

    es6能处理大于两个字节的字符,es5会将字符解析成乱码

    遍历接口

    遍历输出例子:

    {
        let s = '\u{20bb7}abc';
        for(let i=0;i<s.length;i++){
            console.log('es5:', s[i]);
        }
    
        for(let j of s){  //es6循环遍历能输出大于两个字节的字符
            console.log('es6:',j);
        }
    }
    

    模板字符串

    实现模板字符串的例子:

    {
        let name = 'list';
        let info = 'hello world!';
        let a = `I am ${name},${info}`;
        console.log(a);
    }
    

    新增方法(10种)

    1.includes(str)
    判断字符串中是否包含某字符

    2.startsWith(str)
    判断是否以某字符为开始

    3.endsWith(str)
    判断是否以某字符为结束

    4.repeat(num)
    复制num次字符串

    5.padStart(num,str) padEnd(num,str)
    补全位数,前面补全或后面补全
    例子:
    一般常用于处理时间日期等

    {
        //处理时间,补全位数
        console.log('1'.padStart(2,'0')); //固定两位,前面补全
        console.log('1'.padEnd(2,'0')); //固定两位,后面补全
    
    }
    

    6.String.raw(str)
    帮转义字符转义,实现原转义字符的输出,使用场景不多

    *标签模板

    例子:

    {
        let user = {
            name:'list',
            info:'hello world'
        };
        console.log(abc `i am ${user.name},${user.info}`); //处理多语言转换
        function abc(s,v1,v2){
            console.log(s,v1,v2);
            return s + v1 + v2;
        }
    }
    

    数值拓展

    新增方法

    1.多进制表示方法
    0b - 二进制
    0o - 八进制

    2.Number.isFinite(number) - 用处不大
    判断一个数是否有穷

    3.Number.isNaN(number) - 用处不大
    判断是否非数字

    4.Number.isInteger(number) - 常用
    判断一个数是否是整数

    5.数值必须要在一个范围内才有效
    -2的53次方 ~ 2的53次方
    Number.MAX_SAFE_INTEGER
    Number.MIN_SAFE_INTEGER

    6.Number.isSafeInteger(number)
    判断一个数是否在有效范围

    方法调整

    7.Math.trunc(number)
    取一个小数的整数部分

    8.Math.sign(number)
    返回正数还是负数
    返回值:1 0 -1 NaN

    9.Math.cbrt(number)
    求立方根

    数组拓展

    Array.of()

    把一组数据变量转变成数据类型
    不能使用forEach遍历

    Array.from()

    • 把一个集合真正转化成一个数组
    • 对一个数组中的元素遍历操作
    {
      console.log(Array.from([1,3,5],function(item){return item*2}));
    }
    

    [].fill(repalce,start,end)

    替换数组中的元素值
    repalce - 替换内容
    start - 开始位置
    end - 结束位置

    ['1','c','ks'].keys() - 使用频率较高

    获取数组的索引集合

    ['1','c','ks'].values() - 使用频率较高

    获取数组的值集合
    PS:浏览器使用有兼容性问题,必须要引入babel-polyfill插件

    ['1','c','ks'].entries() - 使用频率较高

    获取数组的索引,值的集合

    例子:

    for(let [index,value] of ['1','c','ks'].entries()){
        console.log('values',index,value);
      }
    

    [].find(function(){})

    返回第一个符合条件的数组成员

    [].findIndex(function(){})

    返回第一个符合条件的数组成员的索引

    [].includes(number)

    数组中是否包含某个值

    函数拓展

    默认参数值

    例子:

    {
      function test(x = 'aaa', y = 'world'){
        console.log('默认值',x,y);
      }
      test();
      test('hello');
      test('hello','kill');
    }
    

    输出结果:
    aaa world
    hello world
    hello kill

    作用域的概念

    例子说明:

    {
      let x='test';
      function test2(x,y=x){
        console.log('作用域',x,y);
      }
      test2('kill');
      test2();
    }
    

    块作用域定义了一个x块变量,值为test;
    function作用域重新定义了一个局部变量x,y等同于局部函数作用域变量x,值为undefined
    test2('kill')执行,赋值x为kill,所以y的值为kill
    输出结果为作用域 kill kill

    {
      function test3(...arg){ 
        for(let v of arg){
          console.log('rest',v);
        }
      }
      test3(1,2,3,4,'a');
    }
    

    ...arg表示把离散的值转化成一个数组,适用于参数未知的情况

    {
      console.log(...[1,2,4]);   
      console.log('a',...[1,2,4]);
    }
    

    ...[1,2,3]写法表示把数组转化成离散值

    {
      function tail(x){  
        console.log('tail',x);
      }
      function fx(x){
        return tail(x)
      }
      fx(123)
    }
    

    一个函数的内部返回另一个函数,称为伪调用
    一般用在循环遍历函数或嵌套函数中,提升性能

    对象拓展

    简洁表示法

    {
      // 简洁表示法
      let o=1;
      let k=2;
      let es5={
        o:o,
        k:k
      };
      let es6={
        o,
        k
      };
      console.log(es5,es6);
    
      let es5_method={
        hello:function(){
          console.log('hello');
        }
      };
      let es6_method={
        hello(){
          console.log('hello');
        }
      };
      console.log(es5_method.hello(),es6_method.hello());
    }
    

    属性表达式

    {
      // 属性表达式
      let a='b';
      let es5_obj={
        a:'c',
        b:'c'
      };
    
      let es6_obj={
        [a]:'c'
      }
    
      console.log(es5_obj,es6_obj);
    
    }
    

    其中es6——obj中的[a]中的a可以是个表达式或变量

    新增的API

    {
      // 新增API
      console.log('字符串',Object.is('abc','abc'),'abc'==='abc');
      console.log('数组',Object.is([],[]),[]===[]);
    
      console.log('拷贝',Object.assign({a:'a'},{b:'b'}));
    
      let test={k:123,o:456};
      for(let [key,value] of Object.entries(test)){
        console.log([key,value]);
      }
    }
    

    Object.is - 判断是否完全相等
    Object.assign - 拷贝对象,返回拷贝后的对象,是浅拷贝,如果对象有继承或有引用类型,继承或引用的具体内容不会拷贝

    Symbol

    声明一个独一无二的变量

    1.Symbol()

    2.Symbol.for('a1')

    {
      let a1=Symbol.for('abc');
      let obj={
        [a1]:'123',
        'abc':345,
        'c':456
      };
      console.log('obj',obj);
    
      for(let [key,value] of Object.entries(obj)){ //仅能拿到对象中非Symbol类型的属性
        console.log('let of',key,value);
      }
    
      Object.getOwnPropertySymbols(obj).forEach(function(item){ //getOwnPropertySymbols取对象的所有Symbol类型的属性
        console.log(item);
        console.log(obj[item]);
      })
    
      Reflect.ownKeys(obj).forEach(function(item){ //不仅能拿到Symbol类型的也能拿到非Symbol类型的属性
        console.log('ownkeys',item,obj[item]);
      })
    }
    

    首先定义Symbol类型的属性,使用对象的表达式属性方式;
    let [key,value] of Object.entries(obj)
    仅能获取对象的非Symbol类型的属性

    Object.getOwnPropertySymbols(obj)
    仅能获取对象的Symbol类型的属性

    Reflect.ownKeys(obj)
    不仅能拿到Symbol类型的也能拿到非Symbol类型的属性

    数据结构

    Set的用法

    表示一个集合。

    {
      let list = new Set();
      list.add(5);
      list.add(7);
    
      console.log('size',list.size);
    }
    {
      let arr = [1,2,3,4,5];
      let list = new Set(arr);
    
      console.log('size',list.size);
    }
    {
      let list = new Set();
      list.add(1);
      list.add(2);
      list.add(1);
    
      console.log('list',list); //输出list Set(2) {1, 2}
    
      let arr=[1,2,3,1,'2'];
      let list2=new Set(arr);
    
      console.log('unique',list2);
    }
    

    1.set中增加元素要用add方法;
    2.获取集合中的元素个数用size属性;
    3.set可以把数组转化成集合数据类型;
    4.set中的元素都是唯一的,add相同的元素不会报错,只会不起效,可用于去重功能;

    {
      let arr=['add','delete','clear','has'];
      let list=new Set(arr);
    
      console.log('has',list.has('add'));
      console.log('delete',list.delete('add'),list);
      list.clear();
      console.log('list',list);
    }
    

    list.has() - 集合中是否含有元素

    list.delete() - 删除元素

    list.clear() - 清空集合

    list.add() - 增加元素

    Set实例的遍历
    {
      let arr=['add','delete','clear','has'];
      let list=new Set(arr);
    
      for(let key of list.keys()){
        console.log('keys',key);
      }
      for(let value of list.values()){
        console.log('value',value);
      }
      for(let [key,value] of list.entries()){
        console.log('entries',key,value);
      }
    
      list.forEach(function(item){console.log(item);})
    }
    

    Set集合的遍历跟数组的遍历方法类似,keys和value值相同,都是元素值
    keys() - 取集合的索引
    values() - 取集合的值
    entries() - 取集合的索引和值

    WeakSet

    1.只能放对象,不能放其他基本类型;
    2.没有垃圾回收机制,没有clear方法,没有set属性,不能遍历;

    Map的用法

    1.添加元素Map.set()和获取Map中key索引对应值Map.get()

    {
      let map = new Map();
      let arr=['123'];
    
      map.set(arr,456);
    
      console.log('map',map,map.get(arr));
    }
    

    map中设置key为一个数组;
    map.get获取索引对应值;

    2.map创建的方式

    {
      let map = new Map([['a',123],['b',456]]);
      console.log('map args',map);
      console.log('size',map.size);
      console.log('delete',map.delete('a'),map);
      console.log('clear',map.clear(),map);
    }
    

    等同于

    {
      let map2 = new Map();
      map2.set('a',123);
      map2.set('b',456);
      console.log('map2 args',map2);
      console.log('size',map2.size);
      console.log('delete',map2.delete('a'),map2);
      console.log('clear',map2.clear(),map2);
    }
    

    delete,clear方法与set类似。

    WeakMap

    与Map的区别:
    1.只能放对象,不能放其他基本类型;
    2.没有垃圾回收机制,没有clear方法,没有set属性,不能遍历;

    map-set与数组和对象的区别

    Map和Array的相比

    {
      //数据结构横向对比,增删改查
      let map = new Map();
      let array = [];
    
      //增
      map.set('t',123);
      array.push({t:123});
    
      console.info('map-array',map,array);
    
      //查
      let map_exist = map.has('t');
      let array_exist = array.find(item=>item.t);
    
      console.info('map-array',map_exist,array_exist);
    
      //改
      map.set('t',2);
      array.forEach(item=>item.t?item.t=2:'');
      console.info('map-array',map,array);
    
      //删
      map.delete('t');
      let index = array.findIndex(item=>item.t);
      array.splice(index,1);
      console.info('map-array',map,array);
    }
    

    Set和Array的相比

    {
      //Set和Array的对比
      let set = new Set();
      let array = [];
    
      //增
      let obj = {t:1};
      set.add(obj);
      array.push(obj);
      console.info('set-array',set,array);
    
      //查
      let set_exist = set.has(obj);
      let array_exist = array.find(item=>item.t);
      console.info('set-array',set_exist,array_exist);
    
      //改
      set.forEach(item=>item.t?item.t=2:'');
      array.forEach(item=>item.t?item.t=2:'');
      console.info('set-array',set,array);
    
      //删
      set.forEach(item=>item.t?set.delete(item):'');
      let index = array.findIndex(item=>item.t);
      array.splice(index,1);
      console.info('set-array',set,array);
    }
    

    map,set和object的对比

    {
      //map,set,object对比
      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.info('map-set-array',map,set,obj);
    
      //查
      console.log({
        map_exist:map.has('t'),
        set_exist:set.has(item),
        obj_exist:'t' in obj
      })
    
      //改
      map.set('t',2);
      item['t'] = 2;
      obj['t'] = 2;
      console.info('map-set-array',map,set,obj);
    
      //删
      map.delete('t');
      set.delete(item);
      delete obj['t'];
      console.info('map-set-array',map,set,obj);  
    }
    

    综上总结:
    整个数据开发过程中涉及数据结构,能使用map就不使用数组,特别是不使用数组;
    优先使用map,如果对数据要求比较高,对数据结构存储的唯一性要求,要考虑使用set,反正优先使用map和set,放弃传统的数组和object;

    Proxy和Reflect

    Proxy - 代理

    1.有一个原始数据对象
    2.通过Proxy拦截,代理生成一个新的处理后的对象数据返回

    • get()
      当对象获取属性时触发,进行拦截代理

    -set()
    当对象设置属性时触发,进行拦截代理

    • has()
      拦截key in object操作
      返回值是true和false

    • deleteProperty()
      拦截删除属性操作

    • ownKeys()
      拦截Object.keys,Object.getOwnPropertySymbols,Object.getOwnPropertyNames

    2.Reflect - 反射

    • Reflect.get(obj,'time')
      读取对象的属性

    • Reflect.set(obj,'name','mukewang')
      设置对象的属性

    • Reflect.has(obj,'name')
      判断对象是否存在该属性

    Proxy使用场景例子:

    {
      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 target[key];
              }else{
                throw Error(`不能设置${key} 到 ${value}`);
              }
            }else{
              throw Error(`${key} 不存在`);
            }
          }
        });
      }
    
      const PersonValidator = {
        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,PersonValidator);
        }
      }
    
      let p = new Person('lincimy',30);
      console.log(p);
      p.a = 1;
      p.name = 12;
    }
    

    总结:使用Proxy,通过代理的方式把条件和对象本身也就是业务逻辑分离,在后续代码维护和健壮性有很好的作用。

    类和对象

    基本用法
    {
      // 基本定义和生成实例
      class Parent{
        constructor(name='mukewang'){
          this.name=name;
        }
      }
      let v_parent=new Parent('v');
      console.log('构造函数和实例',v_parent);
    }
    
    继承
      class Child extends Parent{
    
      } 
    

    如果子类要传递参数,对父类默认值进行覆盖,使用super方法:

    {
      // 继承传递参数
      class Parent{
        constructor(name='mukewang'){
          this.name=name;
        }
      }
    
      class Child extends Parent{
        constructor(name='child'){
          super(name); //要覆盖父类的什么参数,就在这里传参
          this.type='child'; //自定义参数要在super之后,否则报错
        }
      }
    
      console.log('继承传递参数',new Child('hello'));
    }
    
    getter和setter
    {
      // getter,setter
      class Parent{
        constructor(name='mukewang'){
          this.name=name;
        }
    
        get longName(){ //longName属性获取
          return 'mk'+this.name
        }
    
        set longName(value){ //longName属性设置
          this.name=value;
        }
      }
    
      let v=new Parent();
      console.log('getter',v.longName);
      v.longName='hello';
      console.log('setter',v.longName);
    }
    
    静态方法 - 加了static

    静态方法是通过类去调用,而不是通过类的实例去调用

    {
      // 静态方法
      class Parent{
        constructor(name='mukewang'){
          this.name=name;
        }
    
        static tell(){
          console.log('tell');
        }
      }
    
      Parent.tell();
    
    }
    
    静态属性

    静态属性在ES6中没有关键词

    {
      // 静态属性
      class Parent{
        constructor(name='mukewang'){
          this.name=name;
        }
    
        static tell(){
          console.log('tell');
        }
      }
    
      Parent.type='test';
    
      console.log('静态属性',Parent.type);
    
    
    }
    

    在类定义完之后,直接在类上定义,而不是实例,之后读取就是类的静态属性;

    Promise - 解决异步操作问题

    原始用法 - 使用callback回调函数
    缺点:如果回调函数过多,导致无法清晰逻辑操作的执行顺序

    使用Promise例子:

    {
      let ajax=function(){
        console.log('执行2');
        return new Promise(function(resolve,reject){
          setTimeout(function () {
            resolve()
          }, 1000);
        })
      };
    
      ajax().then(function(){
        console.log('promise','timeout2');
      })
    }
    

    与ES5的回调方法在结果上来说是一致的,但在代码的可读性和维护性上是非常有优势的。

    Promise中捕获错误:

    {
      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',3);
      }).catch(function(err){
        console.log('catch',err);
      });
    }
    
    Promise高级用法

    1.Promise.all()

    {
      // 所有图片都加载完再添加到页面
      function loadImg(src){
        return new Promise((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(item){
          document.body.appendChild(item);
        });
      }
    
      Promise.all([
        loadImg('https://upload.jianshu.io/admin_banners/web_images/3995/97984254f407672e5ca56e4aa66ad9e4330e3e0b.jpg?imageMogr2/auto-orient/strip|imageView2/1/w/1250/h/540'),
        loadImg('https://upload.jianshu.io/admin_banners/web_images/3989/986f00c9a5ab4406b143b8985f925258bba06b9d.jpg?imageMogr2/auto-orient/strip|imageView2/1/w/1250/h/540'),
        loadImg('https://upload.jianshu.io/admin_banners/web_images/3990/4a0679fb9dde465cd13797299699be750382b04c.jpg?imageMogr2/auto-orient/strip|imageView2/1/w/1250/h/540')
      ]).then(showImgs);
    }
    

    Promise.all中元素promise全部返回有所变化,promise.all总元素才会有所触发,触发then中操作执行;

    2.Promise.race()

    {
      // 所有图片都加载完再添加到页面
      function loadImg(src){
        return new Promise((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);
      }
    
      Promise.race([
        loadImg('https://upload.jianshu.io/admin_banners/web_images/3995/97984254f407672e5ca56e4aa66ad9e4330e3e0b.jpg?imageMogr2/auto-orient/strip|imageView2/1/w/1250/h/540'),
        loadImg('https://upload.jianshu.io/admin_banners/web_images/3989/986f00c9a5ab4406b143b8985f925258bba06b9d.jpg?imageMogr2/auto-orient/strip|imageView2/1/w/1250/h/540'),
        loadImg('https://upload.jianshu.io/admin_banners/web_images/3990/4a0679fb9dde465cd13797299699be750382b04c.jpg?imageMogr2/auto-orient/strip|imageView2/1/w/1250/h/540')
      ]).then(showImgs);
    }
    

    Promise.race中元素只要有一个状态发生了变化,就会触发后续操作,即.then中的逻辑操作;

    Iterator和for...of循环

    自定义部署对象的Iterator:

    {
      let obj={
        start:[1,3,2],
        end:[7,9,8],
        [Symbol.iterator](){
          let self=this;
          let index=0;
          let arr=self.start.concat(self.end);
          let len=arr.length;
          return {
            next(){
              if(index<len){
                return {
                  value:arr[index++],
                  done:false
                }
              }else{
                return {
                  value:arr[index++],
                  done:true
                }
              }
            }
          }
        }
      }
      for(let key of obj){
        console.log(key);
      }
    }
    

    Generator - 异步操作

    基本定义用法:

    {
      // genertaor基本定义
      let tell=function* (){
        yield 'a';
        yield 'b';
        return 'c'
      };
    
      let k=tell();
    
      console.log(k.next());
      console.log(k.next());
      console.log(k.next());
      console.log(k.next());
    }
    

    使用场景:
    1.抽奖次数限制

    {
      let draw = function(count){
        //具体抽奖逻辑
        console.log(`剩余${count}次`);
      }
    
      let residue = function* (count){
        while(count>0){
          count--;
          yield draw(count);
        }
      }
    
      let star = residue(5);
      let btn = document.createElement('button');
      btn.id = 'start';
      btn.textContent = '抽奖';
      document.body.appendChild(btn);
      document.getElementById('start').addEventListener('click',function(){
        star.next()
      },false);
    }
    

    2.长轮询 - 服务端的某个数据状态定期变化,前端展示需要定期取状态

    Decorator - 修饰器

    1.是个函数;
    2.修改行为;
    3.修改类的行为;

    {
      let readonly=function(target,name,descriptor){
        descriptor.writable=false;
        return descriptor
      };
    
      class Test{
        @readonly
        time(){
          return '2017-03-11'
        }
      }
    
      let test=new Test();
    
      // test.time=function(){
      //   console.log('reset time');
      // };
    
      console.log(test.time());
    }
    

    当设置类中的函数为不可修改时,当实例尝试对类中的方法进行修改,即报错~

    模块化

    1.模块的引入 - import
    2.模块的带出 - export

    let A=123;
    let test=function(){
      console.log('test');
    }
    class Hello{
      test(){
        console.log('class');
      }
    }
    
    export default {
      A,
      test,
      Hello
    }
    
    import lesson from './class/lesson17';
    console.log(lesson.A,lesson.test,lesson.Hello);
    

    相关文章

      网友评论

        本文标题:ES6语法

        本文链接:https://www.haomeiwen.com/subject/wicqgxtx.html