ES6语法

作用域的概念

  • 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

模板字符串

实现模板字符串的例子:

{
    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

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语法)