ES6语法

一、let和const

es6之前有两个作用域:全局作用域、函数作用域
es6新增加了块作用域,也就是{}包起来的代码

function test() {
    for (let i=1;i<3;i++){
        console.log(i);
    }
    console.log(i);//error: i is not defined
}

为什么报错?因为es6强制开启了严格模式,变量未声明不能引用

let a=3;
let a=4;

报错,不能重复声明!

const PI=3.14;

定义常量,常量不能修改!也是有块作用域的!并且,声明的时候必须赋值!

const PI=3.14,
      k={
        a:1
      };
k.b=3;
console.log(PI,k);

可以输出。是因为k是对象,是引用类型,返回的是对象存储内存的指针,发生了修改也可以输出。
const和let的唯一区别就是,const不可以被更改,所以当声明变量的时候,尤其是在声明容易被更改的全局变量的时候,尽量使用const。

  • 更好的代码语义化,一眼看到就是常量。
  • 另一个原因是因为JavaScript 编译器对const的优化要比let好,多使用const,有利于提高程序的运行效率。
  • 所有的函数都应该设置为常量。

二、解构赋值

解构赋值的分类:数组结构赋值(左右都是数组)、对象结构赋值(左右都是对象)、字符串结构赋值(左数组、右字符串)、布尔值结构赋值、函数参数解构赋值(数组解构赋值在函数上的引用)、数值解构赋值

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

如果c没有赋值,找不到可以配对的值,c就是undifined。
适用场景:变量交换,选择性获取返回值

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

上面这两种也可以混合使用。
在用到数组成员对变量赋值时,尽量使用解构赋值。
对象的解构赋值::

{
    let o={p:42,q:true};
    let {p,q}=o;
    console.log(p, q);//42 true
}
{
    let {a=10,b=5}={a:3};
    console.log(a, b);//3 5  a=10是默认值,找不到匹配项时才=10
}

使用场景:

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

函数的参数如果是对象的成员,优先使用解构赋值。
如果函数返回多个值,优先使用对象的解构赋值,而不是数组的解构赋值。这样便于以后添加返回值,以及更改返回值的顺序。

三、正则扩展

正则新增特性:u修饰符、y修饰符、s修饰符

{
    //es5
    let regex=new RegExp('xyz','i');
    let regex2=new RegExp(/xyz/i);//或者直接/xyz/i
    console.log(regex.test('xyz123'));//true
    console.log(regex2.test('xyz123'));//true

    //es6,参数可以下面这样
    let regex3=new RegExp(/xyz/ig,'i');
    console.log(regex3.flags);//i 即第二个参数的修饰符会覆盖前面正则表达式的修饰符
}
{
    //y修饰符 vs g修饰符
    let s='bbb_bb_b';
    let a1=/b+/g;
    let a2=/b+/y;
    console.log('one',a1.exec(s),a2.exec(s));//bbb bbb
    console.log('two',a1.exec(s),a2.exec(s));//bb null
    //相同点:都是全局匹配
    //不同点:g是上一次匹配的下一个字符开始,即_,不强调在第一个字符就能匹配上
    //不同点:y是上一次匹配的下一个字符开始,即_,但是必须得在第一个字符就能匹配上
    console.log(a1.sticky,a2.sticky);//false true 是否开启y
}
{
    //u修饰符:unicode
    console.log('u-1',/^\uDB3D/.test('\uDB3D\uDC2A'));//u-1 true //\uDB3D\uDC2A当成两个字符
    console.log('u-2',/^\uDB3D/u.test('\uDB3D\uDC2A'));//u-2 false //\uDB3D\uDC2A当成一个字符

    console.log(/\u{61}/.test('a'));//false
    console.log(/\u{61}/u.test('a'));//true

    console.log(`\u{20BB7}`);//unicode编码大于FFFF,即大于两个字节
    let s='𠮷';
    console.log(/^.$/.test(s));//false
    console.log(/^.$/u.test(s));//true

    console.log('test',/𠮷{2}/.test('𠮷𠮷'));//test false
    console.log('test2',/𠮷{2}/u.test('𠮷𠮷'));//test2 true
    //总结,大于两个字节长度的字符,要加u
    //但是仍然不能匹配换行符,回车符,行分隔符,段分隔符
    //如果要能匹配,使用s修饰符,但是s修饰符es6尚未实现
}

四、字符串扩展

安装补丁库,处理兼容:npm install babel-polyfill --save-dev
需要引入兼容库:

import 'babel-polyfill';
{
    console.log('a','\u0061');//a a
    console.log('a','\u20BB7');//a ₻7 超过了0xFFF,即两个字节,会被当成两个字符
    console.log('s',`\u{20BB7}`);//s 𠮷
}
{
    let s='𠮷';
    //es5
    console.log('length',s.length);//2 (码字大于两个字节,当四个字节处理,计算长度的时候每两个字节算一个长度)
    console.log('0',s.charAt(0));//0 乱码
    console.log('0',s.charAt(2));//0 乱码
    console.log('at0',s.charCodeAt(0));//at0 55362
    console.log('at1',s.charCodeAt(1));//at0 57271
    //es6
    let s1='𠮷a';
    console.log('length',s1.length);//3
    console.log('code0',s1.codePointAt(0));//134071 取出4个字节
    console.log('code0',s1.codePointAt(0).toString(16));//20bb7
    console.log('code1',s1.codePointAt(1));//57271 取出后两个字节
    console.log('code1',s1.codePointAt(2));//97 就是a
    //.toString(16)转成16进制
}
{
    //es5
    console.log(String.fromCharCode('0x20BB7'));//乱码
    //es6
    console.log(String.fromCodePoint('0x20BB7'));//𠮷
}
{
    let str='\u{20BB7}abc';
    for (let i=0;i<str.length;i++){
        console.log('es5',str[i]);//前两个乱码 a b c
    }
    for (let code of str){
        console.log('es6',code);//𠮷 a b c
    }
}
{
    let str='string';
    console.log('includes',str.includes('r'));//true
    console.log('start',str.startsWith('str'));//true
    console.log('end',str.endsWith('ng'));//true
}
{
    let str='abc';
    //es5是用+
    console.log(str.repeat(2));//abcabc
}
//模板字符串
{
    let name='list';
    let info='hello world';
    let m=`i am ${name},${info}`;
    console.log(m);//i am list,hello world
    console.log('1'.padStart(2,'0'));//01
    console.log('1'.padEnd(2,'0'));//10
}
//标签模板:放置XSS攻击,处理多语言
{
    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);//["i am ", ",", "",] "list" "hello world"
        return s+v1+v2;//i am ,,,listhello world
    }
}
{
    console.log(String.raw`Hi\n${1-2}`);//Hi \n-1
    console.log('Hi\n${1+2}');//Hi 换行 ${1+2}
}

五、数值扩展

{
    console.log(0b11110111);//247 0b二进制(大小写均可)
    console.log(0o11111);//4681 0o八进制(大小写均可)
}
{
    console.log('15',Number.isFinite(15));//true
    console.log('NaN',Number.isFinite(NaN));//false
    console.log('1/0',Number.isFinite(1/0));//false
    console.log('NaN',Number.isNaN(NaN));//true
    console.log('0',Number.isNaN(0));//false

    console.log('25',Number.isInteger(25));//true
    console.log('25.0',Number.isInteger(25.0));//true 25.0=25
    console.log('25.1',Number.isInteger(25.1));//false
    console.log('25.0',Number.isInteger('25.0'));//false

    console.log(Number.MAX_SAFE_INTEGER);
    console.log(Number.MIN_SAFE_INTEGER);
    console.log(Number.isSafeInteger(10));//true 是否位于上面两个数的范围内
    console.log(Number.isSafeInteger('a'));//false

    //es5:Math.floor,Math.ceil
    console.log(4.1,Math.trunc(4.1));//4
    console.log(4.9,Math.trunc(4.9));//4

    console.log('-5',Math.sign(-5));//-1
    console.log('5',Math.sign(5));//1
    console.log('0',Math.sign(0));//0
    console.log('a',Math.sign('a'));//NaN

    //开立方根
    console.log(Math.cbrt(-1));//-1
    console.log(Math.cbrt(8));//2
}

六、数组扩展

{
    let arr=Array.of(3,4,7,9,11);
    console.log('arr',arr);//[3,4,7,9,11]
    console.log('arr',Array.of());//[]
}
{
    let p=document.querySelectorAll('p');
    let pArr=Array.from(p);//将上面的集合转义成数组
    pArr.forEach(function (item) {
        console.log(item.textContent);
    });
    //map
    console.log(Array.from([1,3,5],function (item) {return item+2;}));//3 5 7
    //填充数组
    console.log('fill-7',[1,'a',undefined].fill(7));//[7,7,7]
    console.log('fill,pos',['a','b','c','d','e'].fill(7,1,3));//["a", 7, 7, "d", "e"] 1和3表示起始和截至位置,不包括位置3

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

    console.log([1,2,3,4,5].copyWithin(0,3,4));//[4,2,3,4,5] (从0开始替换,从3开始读取,也就是第一个读取的数是4,4是截至位置,也就是在位置4之前,因此只取4)

    console.log([1,2,3,4,5,6].find(function (item) {
        return item>3;//4,只找第一个
    }));
    console.log([1,2,3,4,5,6].findIndex(function (item) {
        return item>3;//3
    }));
    console.log('number',[1,2,NaN].includes(1));//true
    console.log('number',[1,2,NaN].includes(NaN));//true
}

使用扩展运算符(...)拷贝数组:const itemsCopy = [...items];

七、函数扩展

{
    function test(x, y='world') {
        console.log('默认值',x, y);
    }
    test();//undefined world

    let x='test';
    function test2(x,y=x) {
        console.log('作用域',x,y)
    }
    test2('kill');//kill kill
}
{//rest参数
    function test3(...arg) {//将输入的参数都转为数组
        for (let v of arg){
            console.log('rest',v);//a b c
        }
    }
    test3('a','b','c');

    //将数组转成离散的值
    console.log(...[1,2,4]);//1 2 4
    console.log('a',...[1,2,4]);//a 1 2 4
}
{//箭头函数
    let arrow = v => v+2;//v是参数,v+2是返回值
    console.log('arrow',arrow(3));//5
    //无参数情况下
    let arrow2 = ()=> 2;
}
{//伪调用:函数的最后一句话是不是函数
    function tail(x) {
        console.log('tail',x);
    }
    function fx(x) {
        return tail(x);
    }
    fx(123);//tail 123
}

八、对象扩展

这里的对象指Object对象

{
    // 简洁表达法
    let o=1;
    let k=2;
    let es5={
        o:o,
        k:k
    };
    let es6={
        o,
        k
    };
    console.log(es5,es6);//结果是一样的

    let es5_mrthod={
        hello:function () {
            console.log('hello');
        }
    };
    let es6_method={
        hello(){
            console.log('hello');
        }
    };
    console.log(es5_mrthod,es6_method);//结果是一样的

    //属性表达式
    let a='b';
    let es5_obj={
        a: 'c'
    };
    let es6_obj={
        [a]:'c' //这里的a是变量,即b
    };
    console.log(es5_obj,es6_obj);

    //新增API
    console.log('字符串',Object.is('abc','abc'));//true 相当于===
    console.log('数组',Object.is([],[]),[]===[]);//false false 引用地址不同
    //浅复制(只改引用地址)
    console.log('拷贝',Object.assign({a:'a'},{b:'b'}));//{a: "a", b:"b"}
    let test={k:123,o:456};
    for (let [key,value] of Object.entries(test)){
        console.log(key,value);
    }
}

不要声明之后又给对象添加新属性,如果一定非要加请使用Object.assign。

九、Symbol用法

Symbol的概念:用symbol声明的变量,永远不相等。

{
    //声明1
    let a1=Symbol();
    let a2=Symbol();
    console.log(a1===a2);//false
    //声明2
    let a3=Symbol.for('a3');//'a3'会先检查a3是否在全局注册过,如果是,返回该值
    let a4=Symbol.for('a3');
    console.log(a3===a4);//true
    //使用场景
    let a5=Symbol.for('abc');
    let obj={
        [a5]: '123',
        'abc': 345,
        'c': 456
    };
    console.log(a5,obj);//Symbol(abc) {abc: 345,c: 456, Symbol(abc): "123"}
    for (let [key,value] of Object.entries(obj)){
        console.log('let of',key,value);
    }
    //let of abc 345
    //let of c 456
    Object.getOwnPropertySymbols(obj).forEach(function (item) {
        console.log(obj[item]);//123
    });
    Reflect.ownKeys(obj).forEach(function (item) {
        console.log(item,obj[item]);//可以将所有的key-value值打印出来
    });
}

十、set-map数据结构

数据结构:set、weakset、map、weakmap
Object的key必须是字符串或者Symbol数据类型,而map的key可以是任意数据类型。
weakset与set支持的数据类型不同,weakset的元素只能是数据对象,且weakset中的对象是弱引用(地址引用),即不会检测这个对象是否在其他地方用过,也就意味着不会和垃圾回收机制挂钩(不会检测是否被回收)。

{//set
    let list=new Set();//没有重复值
    list.add(5);
    list.add(7);
    console.log('size',list.size);//2

    let arr=[1,2,3,4,5];
    let list1=new Set(arr);
    console.log('size',list1.size);//5

    let list2=new Set();
    list2.add(1);
    list2.add(2);
    list2.add(1);
    console.log('size',list2.size);//2
    //重要应用场景:去重
    let arr1=[1,2,3,1,2];
    let list3=new Set(arr1);
    console.log('unique',list3);//{1,2,3}
    let arr2=[1,2,3,1,"2"];
    let list4=new Set(arr2);
    console.log('unique',list4);//{1,2,3,"2"}

    let arr3=['add','delete','clear','has'];
    let list5=new Set(arr3);
    console.log(list5.has('add'));//true
    console.log('delete',list5.delete('add'),list5);//true {"delete","clear","has"}
    list5.clear();
    console.log(list5);//set(0)
    //key和value都是一样的
    let list6=new Set(arr3);
    for (let key of list6.keys()){
        console.log('keys',key);
    }
    for (let value of list6.values()){
        console.log('values',value)
    }
    for (let value of list6.values()){
        console.log('values',value)
    }
    for (let [key,value] of list6.entries()){
        console.log(key,value)
    }
    list6.forEach(function (item) {
        console.log(item);
    });
}
{//weakset
    let weakList=new WeakSet();
    let arg={};
    weakList.add(arg);
    //weakList.add(2);//报错
    console.log(weakList);
    //无clear方法,无size属性,不能遍历
}
{//map
    let map=new Map();
    let arr=['123'];
    map.set(arr,459);
    console.log(map,map.get(arr));
    //第二种定义方式
    let map1=new Map([['a',123],['b',456]]);
    console.log(map1);//{"a"=>123,"b"=>456
    console.log('size',map1.size);
    console.log('delete',map.delete('a'),map);
    console.log('clear',map.clear(),map);
    //遍历同set
}
{//weakmap
    let weakMap=new WeakMap();//接收对象必须是对象
    //无size对象,无clear方法,不能遍历
}

十一、map-set与数组和对象的比较

{
    //map与数组的对比
    let map=new Map();
    let array=[];
    //增
    map.set('a',123);
    array.push({a:123});
    console.info('map-array',map, array);
    //查
    let map_exists=map.has('a');//true
    let array_exists=array.find(item =>item.a);//{a:123}
    //改
    map.set('a',2);
    array.forEach(item => item.a?item.a=2:'');
    //删
    map.delete('a');
    let index=array.findIndex(item=>item.a);
    array.splice(index,1);
}
{
    //set和array的对比
    let set=new Set();
    let array=[];
    //增
    set.add({t:1});
    //查
    let set_exist=set.has({t:1});
    //改
    set.forEach(item=>item.t?item.t=2:'');
    //删
    set.forEach(item=>item.t?set.delete(item):'');
}
{
    //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_exists: map.has('t'),
        set_exists: set.has(item),
        obj_exists: 't' in obj
    });
    //改
    map.set('t',2);
    item.t = 2;//set的改,引用类型
    obj['t']=2;
    //删
    map.delete('t');
    set.delete(item);
    delete obj['t'];
}

如果只是简单的key: value结构,建议优先使用Map,因为Map提供方便的遍历机制。

十二、Proxy和Reflect

{
    //proxy:代理
    let obj={ //原始对象,存储真实数据
        time: '2017-08-04',
        name: 'net',
        _r: 123
    };
    let monitor=new Proxy(obj,{//通过Proxy新生成一个对象
        //拦截对象属性的读取
        get(target,key){
            return target[key].replace('2017','2018');
        },
        //拦截对象属性的设置
        set(target,key,value){
            if (key === 'name') {
                return target[key]=value;
            }else{
                return target;//不做任何操作
            }
        },
        //拦截key in Object 操作
        has(target,key){
            if (key === 'name'){
                return target[key];
            } else{
                return false;
            }
        },
        //拦截delete操作符
        deleteProperty(target,key){
            if (key.indexOf('_')>-1){
                delete target[key];
                return true;
            }else{
                return target[key];
            }
        },
        //拦截Object.keys,Object.getOwnPropertySymbols,Object.getOwnPropertNames
        ownKeys(target){
            return Object.keys(target).filter(item=>item!='time');
        }
    });
    //用户使用的是monitor
    console.log(monitor.time);
    monitor.time='2018';
    console.log(monitor.time);//没有变化
    monitor.name = 'com';
    console.log(monitor.name);//com
    console.log('name' in monitor);//true
    delete monitor['time'];
    console.log(monitor);//未删除
    delete monitor._r;
    console.log(monitor);//删除
    console.log(Object.keys(monitor));//"name"
}
{
    //reflect:方法同proxy
    let obj={ //原始对象,存储真实数据
        time: '2017-08-04',
        name: 'net',
        _r: 123
    };
    console.log(Reflect.get(obj,'time'));//2017-08-04
    Reflect.set(obj,'name','com');
    console.log(obj);//com
    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,proxy);
                    }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('lilei',30);
    console.info(person);//Proxy{name:"lilei",age:30}
    person.name=48;//error:不能设置name为48
}

十三、类和对象

{
    //类的基本定义和生成实例
    class Parent{
        //es6中定义构造函数
        constructor(name='com'){
            this.name=name;
        }
    }
    let v_parent=new Parent('net');
    console.info(v_parent);

    //继承
    class Child extends Parent{

    }
    console.log(new Child());//{name:"com"}
    //继承传递参数,将参数传递给父类
    class Child2 extends Parent{
        constructor(name='child'){
            super(name);//super一定放在构造函数的第一行
            this.type='child';
        }
    }
    console.log(new Child2());//{name:"child",type:"child"}

    //getter,setter
    class Parent2{
        constructor(name='com'){
            this.name=name;
        }
        get longName(){
            return 'long'+this.name;
        }
        set longName(value){
            this.name=value;
        }
    }
    let v_parent2=new Parent2();
    v_parent2.longName='net';
    console.log(v_parent2.longName);//longnet

    //静态方法、静态属性
    class Parent3{
        constructor(name='com'){
            this.name=name;
        }
        static tell(){//静态方法
            console.log('tell');
        }
    }
    Parent.type = 'test';//这个就是静态属性
    Parent3.tell();

}

十四、Promise

Promise是异步编程的一种解决方案。

{
    //使用回调的方式
    //缺点:如果是按顺序执行a,b,c...,代码的写法会非常复杂,代码的复杂影响后期的维护
    let ajax=function (callback) {
        console.log('执行');
        setTimeout(function () {
            callback&&callback.call();
        },1000);
    };
    ajax(function () {
        console.log('timeout1');
    });

    //使用promise解决方案
    let ajax1=function () {
        console.log('执行1');
        return new Promise(function (resolve,reject) {
            //resolve:要执行下一步的操作
            //reject:要中断当前的操作
            setTimeout(function () {
                resolve();
            },1000);
        });
    };
    ajax1().then(function () {
        console.log('promise','timeout2');
        return new Promise(function (resolve,reject) {
           setTimeout(function () {
               resolve();
           },1000);
        });
    })
        .then(function () {
        console.log('promise','timeout3');
    });
}
{//捕获错误
    let ajax=function (num) {
        console.log('执行2');
        return new Promise(function (resolve,reject) {
            if (num>5){
                resolve();
            }else {
                throw new Error('出错了');
            }
        });
    };
    ajax(2).then(function () {
        console.log(6);
    }).catch(function (err) {
        console.log(err);
    });
}
{//应用场景
    //所有图片加载完再加载页面
    function loadImg(src) {
        return new Promise((resolve, reject)=>{
            let img=document.createElement('img');
            img.src=src;
            img.onload=function () {//图片加载完成
                resolve(img);
            };
            img.onerror = function () {
                reject(err);
            };
        });
    }
    function showImgs(imgs) {
        imgs.forEach(function (img) {
            document.body.appendChild(img);
        });
    }
    Promise.all([
        loadImg('http://i4.buimg.com/567571/df1ef0720bea6832.png'),
        loadImg('http://i4.buimg.com/567571/2b07ee25b08930ba.png'),
        loadImg('http://i4.buimg.com/567571/2b07ee25b08930ba.png')
    ]).then(showImgs);
}
{//应用场景
    //有一个图片加载完就添加到页面
    function loadImg(src) {
        return new Promise((resolve, reject)=>{
            let img=document.createElement('img');
            img.src=src;
            img.onload=function () {//图片加载完成
                resolve(img);
            };
            img.onerror = function () {
                reject(err);
            };
        });
    }
    function showImgs(img) {
        let p=document.createElement('p');
        p.appendChild(img);
        document.body.appendChild(p);
    }
    Promise.race([
        loadImg('http://i4.buimg.com/567571/df1ef0720bea6832.png'),
        loadImg('http://i4.buimg.com/567571/2b07ee25b08930ba.png'),
        loadImg('http://i4.buimg.com/567571/2b07ee25b08930ba.png')
    ]).then(showImgs);
}

十五、Iterator和for...of循环

{
    let arr=['hello','world'];
    let map=arr[Symbol.iterator]();
    console.log(map.next());//{value:"hello",done:false}
    console.log(map.next());//{value:"world",done:false}
    console.log(map.next());//{value:undefined,done:false}
}
{
    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);//1 3 2 7 9 8
    }
}
{//for...of
    let arr=['hello','world'];
    for (let value of arr){
        console.log(value);//hello world
    }
}

十六、Genertor

Genertor也是异步编程的一种解决方案,但是相对promise更高级一点。

{
    let state=function* (){
        while(1){
            yield 'A';
            yield 'B';
            yield 'C';
        }
    };
    let status=state();
    console.log(status.next());//A done:false
    console.log(status.next());//B done:false
    console.log(status.next());//C done:false
    console.log(status.next());//A done:false
    console.log(status.next());//B done:false
}
{//应用场景:抽奖
    let draw=function (count) {
        //具体抽奖逻辑略
        console.info(`剩余${count}次`);
    };
    let residue=function* (count) {
        while(count>0){
            count--;
            yield draw(count);
        }
    };
    let start=residue(5);
    let btn=document.createElement('button');
    btn.id='start';
    btn.textContent='抽奖';
    document.body.appendChild(btn);
    document.getElementById('start').addEventListener('click',function () {
        start.next();
    },false);
}
{//应用场景:定期向服务端获取数据,使用长轮询
    let ajax=function* () {
        yield new Promise(function (resolve,reject) {
            setTimeout(function () {
                resolve({code:0})
            },200);
        })
    };
    let pull=function () {
        let generator=new ajax();
        let step=generator.next();
        step.value.then(function (d) {//step.value就是promise实例
            if (d.code!=0) {//表示数据未更新
                setTimeout(function () {
                    console.log('wait');
                    pull();
                },1000);
            }else{
                console.log(d);
            }
        });
    };
    pull();
}

十七、Decorators

修饰器:一个函数,用来修改类的行为。
需要安装插件:npm install babel-plugin-transform-decorators-legacy --save-dev
.babelrc:"plugins":["transform-decorators-legacy"]

{
    let readonly=function (target,name,descriptor) {
        //target:修改类本身
        //name:修改属性名称
        //descriptor:属性的描述对象
        descriptor.writable=false;
        return descriptor;
    };
    class Test{
        @readonly //修饰器
        time(){
            return '2017-03-11';
        }
    }
    let test=new Test();
    console.log(test.time());//2017-03-11
    // test.time=function(){
    //     console.log('reset');//error: Cannot assign to read only property 'time' of object
    // };

    //在类外面操作必须在class前
    let typename=function (target,name,descriptor) {
        target.myname='hello';//静态属性
    };
    @typename
    class Test2{

    }
    console.log(Test2.myname);//hello

    //第三方库修饰器的js库:core-decorators(npm install core-decorators)
}
{//应用场景:埋点
    //将埋点系统从业务逻辑中拆离
    let log=(type)=>{
        return function (target,name,descriptor) {
            let src_method=descriptor.value;
            descriptor.value=(...arg)=>{
                src_method.apply(target,arg);
                console.info(`log ${type}`);
            }
        }
    };
    class AD{
        @log('show')
        show(){
            console.log('ad is show');
        }
        @log('type')
        click(){
            console.log('ad is click');
        }
    }
    let ad=new AD();
    ad.show();//ad is show   log show
    ad.click();//ad is click  log type
}

十八、模块化

ES6的模块化语法:引入import、导出export
导出:

export let A=123;
export function test() {
    console.log('test');
}
export class Hello {
    test(){
        console.log('class');
    }
}

导入:

import {A,test,Hello} from "./class/lesson17";
console.log(A, test, Hello);

可以只导入部分变量:

import {A} from "./class/lesson17";
console.log(A);

起别名:

import * as lesson from "./class/lesson17";
console.log(lesson.A);

不给导出数据起名字(推荐):

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

导入:

import lesson from "./class/lesson17";
console.log(lesson.A);
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,179评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,229评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,032评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,533评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,531评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,539评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,916评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,813评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,568评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,654评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,354评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,937评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,918评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,152评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,852评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,378评论 2 342

推荐阅读更多精彩内容

  • 以下内容是我在学习和研究ES6时,对ES6的特性、重点和注意事项的提取、精练和总结,可以做为ES6特性的字典;在本...
    科研者阅读 3,108评论 2 9
  • [TOC] 参考阮一峰的ECMAScript 6 入门参考深入浅出ES6 let和const let和const都...
    郭子web阅读 1,768评论 0 1
  • 最近在做毕业设计,其中用到了一些 ES6 的语法,比如模块的输出引入,箭头函数,对象字面量的简写,等等。所性顺便就...
    小乌龟变王八阅读 486评论 0 0
  • 作用域的概念 es2015函数作用域全局作用域 es6函数作用域全局作用域块作用域(新增,标识:有大括号包围的)P...
    lincimy阅读 2,671评论 2 1
  • 你说你热爱春天和原野,后来你离开了再熟悉不过的生活,你戴了一块儿表,背了一个双肩包,那个背影定格在我们这群朋友的记...
    面壁yang阅读 199评论 0 2