ES6 读书笔记

一、let和const命令
二、变量的解构赋值
三、字符串的扩展
四、数值的扩展
五、正则的扩展
六、数组的扩展
七、函数的扩展
八、对象的扩展
九、symbol
十、proxy和reflect
十一、二进制数组
十二、set和map数据结构
十三、iterator和for...of循环
十四、generator函数
十五、promise对象
十六、异步操作和async函数
十七、Class
十八、修饰器 (ES7 但babel支持)
十九、module
二十、编程风格[可参阅jscs.info]
 
一、let和const命令
    1.1、let
            {
                let a = 10;
            }
        仅在代码块中使用有效;
        不存在变量提升:需要在声明后使用;
        暂时性死区:只要块级作用域内存在let,其变量便绑定了该区域,不受外部影响;
        不允许重复声明:不允许相同作用域声明同一个变量;
 
    1.2、块级作用域
        由于不存在变量提升,块级作用域之间的元素互不影响。
 
    1.3、const命令
        声明常量,一旦声明,其值不能改变;
        只有声明所在的块级作用域有效;
        不存在变量提升,有暂时性死区;
        对于对象、数组等指针型变量,不能改变的是指针,而非内部内容,如果需要防止内容的改变,使用object.freeze方法。
 
    1.4、跨模块的常量
    // constants.js 模块
        export const A = 1; 
        export const B = 2;
        export const C = 3;
    // test1.js  模块
        import * as constants from ‘./constants’;
        console.log(constants.A);
     // test2.js  模块    
        import {A, B} from ‘./constatns’;
        console.log(A);
 
    1.5 全局对象属性
        window下,全局对象为window;nodejs环境下指的global对象。
        ES6下,var、function命令声明的仍为全局变量;let、const、class命令不属于全局对象属性。
 
二、变量的解构赋值
    2.1 数组的解构赋值
        [a, b, c, d] = [1, 2, 3, 4],这种属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。
        [head, …tail] = [1, 2, 3, 4] // head == 1; tail == [2, 3, 4]
        如果解构不成功,则会赋值undefined
        默认值:[x = 1, y] = [2, 3] or [x = f(), y] = [2, 3];如果默认值为表达式,仅在使用时,才会执行表达式。
 
    2.2 对象的解构赋值
        对象按照属性名取值,数组按照次序取值。
        var {foo: baz, bar: tr} = {foo:’aaa’, bar: ‘bbb’};真正被复制的是baz,而非foo;
        {x} = {x:1} //容易出错,一般会解析成代码块,最佳方式:({x}={x:1})
 
    2.3 字符串的解构赋值
        const [a, b, c, d, e] = ‘hello’;// a=‘h’,b=‘e’…
        let {length: len} = ‘hello’;// len = 5;
 
    2.4 数值与布尔值的解构赋值
        如果右边是数值或布尔值,会先转换成对象。
 
    2.5 函数参数的解构赋值
         undefined会触发函数参数的默认值。
        [1, undefined, 3].map((x = ‘yes’) => x) // [1, ‘yes’, 3]
 
    2.6 圆括号问题
        解析结构是表达式还是模式不容易,所以不要在模式中放置圆括号。
 
    2.7 用途
        a、交换变量
        b、函数返回多个值
        c、函数参数的定义
        d、提取json数据
        e、函数参数的默认值
        f、遍历map结构
 
三、字符串的扩展
    ES6加强了对Unicode的支持,并且扩展了字符串对象。
    javascript允许采用uxxxx形式表示一个字符,其中xxxx表示字符的码点。
    3.1 字符的Unicode表示法
 
    3.2 codePointAt() 可以判断字符是否为4个字节,返回字符对应的码点
 
    3.3 string.fromCodePoint()  参数为码点,可返回字符值
 
    3.4 字符串的遍历器接口
        for (let codePoint of ‘foo’) {
            // ‘f’, ‘o’, ‘o’    其可自动识别四个字节的字符
        }
 
    3.5 at() 可返回四个字节的字符(汉字) 等价两字节的charAt()。
 
    3.6 normalize() 将字符的不同表示方法统一为同样的形式。
 
    3.7 includes(), startsWith(), endsWidth() 表示是否找到参数字符串,返回布尔值
 
    3.8 string.repeat(n) 表示将原字符串重复n次
 
    3.9 padStart, padEnd,用来补全字符串
        ‘x’.padStart(5, ‘ab’) //ababx  接受两个参数,第一个为总长,第二个为重复的字符。
 
    3.10 模板字符串
        使用反引号标识,嵌入变量${}
        $(‘#result’).append(’there are <b>${count}</b>items.’);
 
    3.11 模板编译
 
    3.12 标签模板
        可使用其嵌入其他语言,如jsx。
         函数调用的一种特殊形式,标签指函数,紧跟其后的模版字符串是参数。
        tag`hello ${a + b} world ${a * b}` => function tag([‘hello’, ‘ world’, ‘’], 15, 50)
 
    3.13 string.raw() 充当模板字符串的处理函数,返回一个反斜线都被转移的字符串。
        
四、正则的扩展
    4.1 RegExp构造函数 new RegExp(/abc/ig, ‘i’).flag // ‘i’
 
    4.2 将四个正则方法:match、replace、search、split四个方法都定义在了RegExp的对象上
 
    4.3 u修饰符 为正则添加了u修饰符,含义为’unicode模式’
        a、点字符 .表示任意字符,对于四字节字符,无法匹配,配合修饰符u,可正确判断。
        b、unicode字符表示法 新增了大括号表示Unicode字符 /u{61}/u.test(‘a’)
        c、量词 /接{2}/u.test('接’) //true
        e、预定义模式/^S$/u.test(‘接’) // true
        f、i修饰符
 
    4.4 y修饰符 ‘粘连’修饰符 与g功能相同,不同之处y默认带^,下一位置就必须能够匹配上。
 
    4.5 sticky属性 表示是否设置了y修饰符 var r = /hello/y;  r.sticky // true
 
    4.6 flags属性 返回正则的修饰符
 
    4.7 RegExp.escape() 还未通过审核
 
五、数值的扩展
    5.1 二进制和八进制数值表示法
        0b || 0B 为二进制; 0o || 0O表示八进制
 
    5.2 Number.isFinite(), Number.isNaN() 分别用来检查 Infinite 和 NaN这两个特殊值。
        传统的这两个方法,会先调用Number()转为数字,在判断;而新方法不转换,直接判断。
 
    5.3 Number.parseInt(), Number.parseFloat() 其行为不变,只是移植到了Number对象上。
 
    5.4 Number.isInteger()用来判断是否为整数,3和3.0视为同一值。
 
    5.5 Number.EPSILON 一个极小的常量,为了减小浮点数相减的误差而设,如果误差小于这个常量,则正确。
        5.5545656563e-17 < Number.EPSILON
 
    5.6 安全整数和Number.isSafeInteger()  
        ES6提供了两个常量,Number.MAX_SAFE_INTEGER和Number.MIN_SAFE_INTEGER
 
    5.7 Math对象的扩展
        增加了17个与数学相关的方法。
        a、Math.trunc() 去除数字的小数部分,返回整数部分。
        b、Math.sign() 判断一个数是正数、负数还是零,+1正数;-1负数;+0; -0; NaN
        c、Math.cbrt() 计算一个数的立方根
        d、Math.clz32() 返回一个32位无符号整数形式(使用二进制表示的)有多少个前导0
        e、Math.imul() 返回两个数以32位带符号整数相乘的结果
        f、Math.fround() 返回一个数的单精度浮点数形式
        g、Math.hypot() 返回所有参数的平方和的平方根
        对数方法:
        h、Math.epm1(x) 返回e^x-1
        i、Math.log1p(x) 返回 1/ln(1+x)
        j、Math.log10(x) 返回10为底的x的对数 Math.log10(10000) //4
        k、Math.log2(x) 返回以2为底x的对数
        三角函数方法:
        l、Math.sinh(x)   返回x的双曲正弦
        m、Math.cosh(x) 返回x的双曲余弦
        n、Math.tanh(x)    返回x的双曲正切
        o、Math.asinh(x)    返回x的反双曲正弦
        p、Math.acosh(x)    返回x的反双曲余弦
        q、Math.atanh(x)    返回x的反双曲正切
  5.8 指数运算符 **
   2 ** 3 = 8
 
六、数组的扩展
    6.1、Array.from() 将两类对象转换成真正的数组:类数组的对象及可遍历的对象(即必须有length属性)
        如dom操作的nodeloost集合、函数内部arguments对象及ES6的Set和Map方法
        document.querySelectorAll(‘p’)
        tips: 运算符...也可将某些结构转换成数组;from能正确的识别unicode字符
        Array.from(spans, s => s.textContent);其转换数组的同时,具备map的功能。
 
    6.2、Array.of()
        用于将一组值转换为数组。Array.of(3, 11, 8) // [3, 11, 8]
 
    6.3、copyWithin(target, start = 0, end = this.length)
        将数组内部指定位置的成员复制到其他位置上
 
    6.4、find()和findIndex()
        find找出第一个符合条件的数组成员,返回成员或者undefined
        [1, 4, -5, 10].find((n) => n<0) //-5
        findIndex()与上同,返回成员位置,否则返回-1
 
    6.5、fill(x, start, end)
        填充数组[‘a’, ‘b’].fill(7, 1, 2) // [‘a', 7]
 
    6.6、 entries()、keys()、values() 
        用于遍历数组,返回一个遍历器对象,可用for..of遍历
        entries为遍历键值对;keys为遍历键值;values为遍历值
        for (let [index, elem] of [‘a’, ‘b’].entries()) // 0 ‘a’
 
    6.7、includes(x, start, end)
        返回一个布尔值,表示某个数组是否包含给定的值
 
    6.8、数组的空位
        [, , ,]空位不代表undefined
        ES5对空位的处理不一致,而ES6进行统一,将空位都转换为undefined,空位不会被忽略掉。尽量避免空位出现。
 
    6.9、数组推导
        var a1 = [1, 2, 3,4];
        var a2 = [for (i of a1) i* 2]; //[2, 4, 6, 8]
        var a3 = [for (i of a1) if (i > 2) i]; //[3, 4]
        其可替代map()及filter()方法
 
七、函数的扩展
    7.1、函数参数的默认值
         function log(x, y = ‘hello’){}
        a、参数的解构赋值:重点区分参数的默认值与解构赋值的默认值。
        b、默认参数:非显示的输入undefined,触发该参数等于默认值,null没有这个效果。
        c、length属性:指定默认值的参数,不计入length,导致length失真。
        d、作用域:当前函数作用域与全局作用域
            try catch err throw
 
    7.2、rest参数 “…变量名”
        rest参数搭配的变量是一个数组,将多余的参数放入其中;rest参数之后不能再有参数。
 
    7.3、扩展运算符
        ‘…’,将一个数组转为用逗号分隔的参数序列。
        a、替代apply()
        b、合并数组:[1, 2, …more]
        c、与解构赋值结合:[1, 2, …rest] = list;     
            tips:扩展运算符用于数组赋值时,只能放在末尾。
        d、字符串:[…’hello’] //[‘h’, ‘e’, ‘l’, ‘l’, ‘o’]
            可正确返回字符的长度(可识别unicode字符);[...string].length
        e、类数组对象:可转变成数组.
 
    7.4、name属性
        function foo(){} foo.name // “foo"
 
    7.5、箭头函数
        使用箭头定义函数;
        a、var f = v => v;  等同于 var f = function(v) {return v};
        b、函数不需要参数或者需要多个参数,就用()代替:
             var f = () => v;  等同于 var f = function(a, b) {…… return v};
        c、由于大括号被解析成代码块,如果需要返回对象,需要加上括号:
            var fun = id => ({id: id, name: ‘hity’});
        d、如果代码块多余一条语句,就需要用大括号包起来。
        e、嵌套箭头函数
        tips:
            a、函数体内的this,是定义时的对象,而非运行时;
            b、不可当构造函数;
            c、arguments对象不存在,可用rest参数代替;
            d、不可使用yield命令,无法用作generator函数;
            e、箭头函数无自己的this作用域,this指向父级this;所以无法使用apply、call、bind改变this指向
            f、无arguments、super、new.target;
 
    7.6、函数绑定
            ‘::’可以将左边对象作为上下文绑定到右边的函数上。可以采用链式的写法,返回的还是原对象。
 
    7.7、尾调用优化
            概念:指某个函数的最后一步是调用另外一个函数:function f(x){ return g(x);}
            尾调用优化,去掉外层的调用帧。
                tips:仅当内部函数不需要使用外部函数的变量时,优化才会进行。
            尾递归:递归非常消耗内存,将其转变为尾递归将只有o(1)的复杂度。
                tips:尾递归仅严格模式下可用:“use strict”,这种情况下函数的信息都将移除~
  
八、对象的扩展
    8.1、属性的简洁表示法
        {x, y} == {x: x, y: y};
        var obj = {
            birth,
            method() {
                return ‘hello';
            }
        }
 
    8.2、属性名表达式
        let obj = {
            [prop]: true,
            [‘a’ + ‘b’]: 123
        }
 
    8.3、方法的name属性
        (new Function()).name //anonymous
        bind创造的方法,name属性返回“bound”加原函数名。
 
    8.4、Object.is()
        比较两个值是否严格相等。与 === 基本一致。(+0, -0)//false  (NaN, NaN)// true
 
    8.5、Object.assign(targetObj, srcObj)
        作用:将srcObj的所有可枚举对象复制到targetObj上;其只复制自身属性,不可枚举的和继承的不会被复制。
 
    8.6、属性的可枚举性
        object.getOwnPropertyDescriptor(obj, ‘foo’);
        // {value: 123, writable: true, enumerable: true, configurable: true}
        有三个操作会忽略enumerable为false的属性:
            a、for…in:遍历自身和继承的可枚举属性;
            b、Object.keys():返回对象自身的可枚举属性键名;
            c、JSON.stringify():串行化对象自身的可枚举属性;
            d、Object.assign():复制自身可枚举的属性;
            e、Reflect.enumerate():返回所有for...in循环会遍历的属性
        tips:所有Class的原型的方法都不可枚举。
 
    8.7、属性的遍历
        ES6共6种方法遍历对象的属性:
        for…in:(无symbol)
        Object.keys():(无symbol)
        Object.getOwnPropertyNames(obj):返回数组,包含对象自身所有属性(无symbol)
        Object.getOwnPropertySymbols(obj):返回数组,包含对象自身的所有symbol属性
        Reflect.ownKeys(obj):返回数组,包含对象自身所有的属性
        Reflect.enumerate(obj):返回一个Iterator对象,遍历对象自身和继承所有可枚举属性(无symbol)
 
    8.8、__proto__属性、Object.setPrototypeOf()、Object.getPrototypeOf()
        __proto__属性用来设置、读取当前对象的prototype对象;但最好不用,而是使用object.setPrototypeOf(object, prototype)、object.getPrototypeOf()、object.create()代替。
 
    8.9、对象的扩展运算符
        rest亦可用于对象,使用方法相同。
        tips:
            a、其为浅复制,如果一个键的值为复合类型,则复制这个值的引用。
            b、不能复制继承自原型对象的属性。
            c、rest对象中存在取值函数get,这个函数会立即执行。
 
九、symbol
    9.1、概述
        引入的原因:解决扩展他人对象属性时的命名冲突。
        javascript的第7种数据类型为:symbol,属性名属于symbol就是独一无二的。
        tips:symbol值不能与其他值运算,它不能添加属性,类似字符串。
             symbol值可转为字符串、布尔值;
 
    9.2、作为属性名的symbol
        a {[mySymbol]:  ‘hello’}
 
    9.3、消除魔术字符串
        指在代码之中多次出现、与代码形成强耦合的某一个具体的字符串或者数字。
 
    9.4、属性名的遍历
        可以设置一些非私有又希望仅内部使用的方法。
 
    9.5、symbol.for(), symbol.keyFor()
        symbol.for(name):查找对应的symbol,查到则返回,并登记在全局中,否则创建一个新的symbol。
        symbol.keyFor(s1):返回已登记的symbol key(即name)。
 
    9.6、内置的symbol值
        
十、Proxy和Reflect
    proxy代理,可以理解成目标对象前架设一“拦截”层,外界访问必须先通过该拦截。
    new Proxy(target, handle);
    10.1、实例方法
        a、get():用于拦截某个属性的读取操作;
        b、set():用于拦截某个属性的赋值操作;
        c、apply(): 用于拦截函数的调用、call和apply操作;
        d、has(): 用于隐藏某些操作,不被in操作符发现;
        e、construct(): 用于拦截new命令;
        f、deleteProperty: 用于拦截delete操作,使得属性不被delete;
        g、defineProperty:用于拦截object.defineProperty(添加新属性)操作;
        h、enumerate():用于拦截for...in循环;
        i、getOwnPropertyDescriptor():用于拦截object.getOwnPropertyDescriptor;
        j、getPrototypeof():用于拦截其运算,以及其他一些操作;
        k、isExtensible():用于拦截其操作;[如果对象是可扩展的(这表示可向对象添加新属性),则为 true;否则为 false。]
        l、ownKeys():用于拦截object.keys操作;
        m、preventExtensions():用于拦截其操作,必须返回布尔值;
        n、setPrototypeOf():用于拦截其方法。
 
    10.2、proxy.revocable()
        返回一个可取消的proxy实例。
 
    10.3、reflect概述
        其设计目的:
        a、将object上明显属于语法层面的方法放到reflect上;
        b、修改某些object的返回结果,让其变得更合理;
        c、让object操作都变成函数行为;
        d、reflect对象的方法与proxy对象的方法一一对应,这样可以直接让proxy对象调用reflect对象完成默认行为。
 
十一、二进制数组(大略的过,需要理解内存之类的计算机原理等)
    设计目的:为了让开发者能够通过javascript与操作系统的原生接口进行二进制通信。
    二进制数组分三类:
    a、arrayBuffer对象:代表原始的二进制数据;
    b、typedArray视图:用于读写简单类型的二进制数据;
    c、dataView视图:用于读写复杂类型的二进制数据。
    typedArray有九种类型数据:int8、uint8、uint8C、int16、uint16、int32、uint32、float32、float64
    dataView有除uint8C外的八种数据类型。
    API用到了二进制数组操作二进制数据的有一下浏览器:
        File API、XMLHttpRequest、Fetch API、Canvas、WebSocket
 
    11.1、arrayBuffer对象
        var buf = new ArrayBuffer(32);
        arrayBuffer.prototype.byteLenth:由于分配内存的操作不一定成功,所以需要通过该字段来判断是否成功;
        arrayBuffer.prototype.slice():允许将内存区域的一部分复制生成一个新的arrayBuffer对象;
        arrayBuffer.isView():返回布尔值,表示参数是否为arrayBuffer的一个试图实例。
 
    11.2、typedArray视图
        其有九个构造函数,对应不同的数据类型;
        形成的数组成员都是一种类型;
        成员都是连续的,不会有空位;
        默认值为0。
 
    11.3、dataView视图
 
    11.4、二进制数组的应用
        a、ajax 返回的类型可以为二进制,设置为arraybuffer or blob;
        b、canvas 类型值为uint8clampedarray
        c、websocket 通过arraybuffer发送或者接收二进制数据;
        d、fetch API 取回的数据为arrayBuffer对象;
        e、file API 如果知道文件为二进制数据类型,也可以将其读取为arrayBuffer对象。
 
十二、set和map数据结构
    12.1、set
    set是一种新的数据结构,其与数组的区别是,没有重复值,成员值都唯一。set本身为构造函数。
    set接受一个数组作为参数,var set =new Set([1, 2, 3, 4, 4]); // [1, 2, 3, 4]。
    set加入的值,不会进行类型转换,判断相等使用的是 ===。 
    set实例的属性和方法:
        set.prototype.size: 返回set成员的总数;
        add(value): 添加某个值,返回set结构本身;
        delete(value):删除某个值,返回一个布尔值;
        has(value): 返回一个布尔值;
        clear():清除所有成员,没有返回值。
    遍历方法:keys()、values()、entries()、forEach()
 
    12.2、weakSet
        为不重复的值的集合,与set的区别:
            a、其成员只能是对象;
            b、其对象为弱对象,垃圾回收机制不考虑它的引用,因此,它是不可遍历的。
        方法:add()、delete()、has();
        其用处为:储存DOM节点,而不用担心这个节点从文档中移除时会发生内存泄漏。
 
    12.3、map
        map类似对象,区别在于键不同,对象的键限制只允许字符串,map的键不受限:
            对象为“字符串-值”的对应,map为“值-值”的对应。
        需要堤防一种情况,键为引用地址的情况:如
            map.set([‘a’], 123);
            map.get([‘a’]); // undefined
            由于数组作为键时,标记的是数组所在的引用地址。
            var k1 = [‘a’];
            map.set(k1, 1234);
            map.get(k1) // 1234
        map的键是跟内存绑在一起的,只要内存地址不一样,就视为两个键。如此解决了同名属性碰撞的问题。
        map的属性和方法:
            size属性:返回成员总数;
            set(key, value):设置键值,并返回整个map的结构;
            get(key):读取key对应的值,找不到则返回undefined;
            has(key):返回布尔值,确认键是否存在;
            delete(key):删除某个键,返回布尔值;
            clear():清除所有成员,没有返回值。
        遍历方法:keys()、values()、entries()、forEach()。
        可使用运算符(...)转换成数组。
        转换:
            a、map转数组(…)
            b、数组转map;
            c、map转对象;
            d、对象转为map;
            e、map转为son(键名为字符串);
            f、json转为map(键名为字符串)。
 
    12.4、weakmap
        weakmap与map类似,但其只接受对象作为键名,键名指向的对象不计入垃圾回收机制。其有助于内存泄漏。
 
十三、iterator和for...of循环
    iterator接口为各种不同的数据提供统一的访问机制。只要部署iterator接口,就可完成遍历操作。
    作用:
        a、为各种数据结构提供统一的、简便的访问接口;
        b、使得数据结构的成员能够按照某种次序排列;
        c、es6创造了一种新的遍历命令for...of循环,iterator接口主要供其消费。
    遍历过程:
        step1、创建指针对象,指向当前数据结构的起始位置;
        step2、第一次调用指针对象的next方法,指向第一个成员;
        step3、第二次调用next方法,指向第二个成员;
        step4、不断调用,直到结束。
    step2时,会返回数据结构当前的成员信息;具体是返回一个包含value和done的对象,value为成员值,done为布尔值,表示遍历是否结束。
    iterator接口需要通过symbol.iterator来部署。
 
    13.3、调用iterator接口的场合
        解构赋值、扩展运算符、其他场合:for...of、array.from()、map()、set()、weakmap()、weakest()、promise.all()、promise.race()。
 
    13.4、字符串的iterator接口
        var string = “lala”;
        var iterator = string[Symbol.iterator]();
        修改遍历器对象。
 
    13.5、iterator接口与generator函数
        Symbol.iterator方法最简单的实现还是generator函数。
 
    13.6、遍历器对象的return()、throw()
        next方法是必须部署的方法,return方法用于for...of循环提前退出时(break、continue或者出错),调用。return方法必须返回一个对象。throw方法配合generator使用。
 
    13.7、for...of循环
        一个数据结构只要部署了Symbol.iterator属性,就可以用for...of循环遍历其成员。
        for… in、for…of
        数组、set、类数组对象[string]:for (let v of arr)
        map:for (var [name, value] of  es6)
 
十四、generator函数
    14.1、简介
        基本概念:Generator函数为ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同。
        Generator是状态机,也是遍历器对象生成器,返回一个遍历器对象。它的两个特征:a、function命令与函数名之间有一个星号;b、内部使用yield定义内部状态。最大特点,暂缓执行函数;通过next做暂缓和停顿。
        其调用后,不执行,而是返回一个iterator对象,需用next方法调用,才执行。
        yield语句无法用在普通函数中,否则出错;且用于表达式中时,需要放在圆括号内。
 
    14.2、next方法的参数
        next方法的参数为yield的执行结果,可向函数体内注入值。
        yield返回值通常为undefined;如果next带有参数,则返回该参数。next传递的参数往往为上一次yield的返回值。
 
    14.3、for…of循环
 
    14.4、Generator.prototype.throw(),可在函数体外抛出错误,函数体内执行。
 
    14.5、Generator.prototype.return()
        可返回给定的值,并终结Generator函数的遍历。
        g.return(“foo”) //{value: “foo”, done:true}
        如果函数内部有try...finally代码块,那么return方法会推迟到finally代码执行完再执行。
 
    14.6、yield语句
        如果Generator函数内部调用另一个Generator函数,默认情况下无效;使用yield*,则生效。yield*表示在函数内部部署了一个for...of循环。
 
    14.7、作为对象属性的Generator函数
        let obj = {
            * myGeneratorMethod() {}
        }
 
    14.8、Generator函数的this
        构造函数返回的是一个内部的指针,可通过bind一个对象,赋予作用域,将this绑定在对象上。
 
    14.9、Generator函数推导
        let squard = (for (n of generator()) n * n);
 
    14.10、含义
        Generator与状态机,其本身包含状态机,不需要额外的外部变量保存状态。
 
    14.11、应用
        a、异步操作的同步表达
            function* main() {
                var result = yield request(url);
                var resp = JSON.parse(result);
            }
 
            function request(url) {
                makeAjaxCall(url, function(response) {
                    it.next(response);
                });
            }
 
            var it = main();
            it.next();
        b、控制流管理
        c、部署iterator接口
                利用Generator函数可以在任意对象上部署Iterator接口。
        d、作为数据结构
            其可以返回一系列的值。
 
十五、promise对象
    15.1、promise的含义
        所谓promise就是一个对象,用来传递异步操作的消息。其有两个特点:
            a、其状态不受外界影响;其有三种状态:pending(进行中)、resolved (已完成,又称”fulfilled”)、rejected(已失败);
            b、一旦状态改变就不会再变,任何时候都可以得到这个结果;
        有了promise对象就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调。
        缺点:
            无法取消promise;如果不设置回调,promise内部抛出的错误不会反应到外部;一般说来,如果事件不断发生,使用stream模式比部署promise更好。
 
    15.2、基本用法
            两个异步之间的调用:
                var p1 = new Promise(function (resolve, reject){})
                var p2 = new Promise(function (resolve, reject){
                    resolve(p1);
                })
            p2的状态为(p1 与 p2)的并集。只要一个为rejected,则为rejected;全部为resolved则为resolved。
 
    15.3、Promise.prototype.then()
        then方法返回一个promise实例(并非前一个实例),此时可以链式的调用then。
 
    15.4、Promise.prototype.catch()
        其是.then(null, rejection)的别名,用于指定发生错误的回调函数;promise在resolve后再抛出错误,并不会被捕获。
        promise的错误具有“冒泡”性质,会一直向后传递,直到捕获为止。最好不在then的第二个参数定义rejected状态的回调,而应使用catch方法。
        catch方法也是返回一个promise实例。
 
    15.5、promise.all()
        promise.all方法用于将多个promise实例包装成一个新的promise实例。
        var p = Promise.all([p1, p2, p3]);其参数必须具有iterator接口,且返回的每个成员都是Promise实例。
        p的状态为:
            a、三者都为resolved,则它为resolved;
            b、只要一个为rejected,则它为rejected;此时第一个被rejected的实例的返回值会传递给回调函数。
 
    15.6、promise.race()
        亦是将多个promise实例包装成一个新的promise实例。只要其中有一个实例改变状态,p的状态也跟着改变。
 
    15.7、promise.resolve()
        其可将现有对象转为promise对象;
        promise.resolve(‘foo’) 等价于 new Promise(resolve => resolve('foo’));
 
    15.8、promise.reject()
        返回一个promise的实例,状态为rejected。
 
    15.9、两个附加方法
        done():为了最终捕获任何可能出现的错误;
        finally():指定不管promise对象最后状态如何都会执行的操作。
 
    15.10、应用
        a、加载图片
        b、Generator与Promise(管理 流程+异步 混合操作)
 
    15.11、async函数(亦是用于取代回调函数解决异步操作)
 
十六、异步操作和async函数
    在ES6诞生前,异步编程的方法大概有4种:
        a、回调函数;
        b、事件监听;
        c、发布、订阅;
        d、promise对象。
        
    16.1、Generator函数
        协程,类似线程,执行到一半转移执行权。yield命令将执行权交给其他协程。
        其数据交换及错误处理:next(x);try{}catch{}.
        fetch返回promise对象。
 
    16.2、thunk函数(结合generator函数进行自动流程管理)
        编译器的“传名调用”,将参数放到一个临时函数中,再将临时函数传入函数体内。这个临时函数就叫thunk函数。
 
    16.3、co模块
        co模块用于Generator函数的自动执行。
        var co = require(‘co’);
        co(gen);
        co(gen).then(function() {
            console.log(‘generator函数执行完毕');
        });
        如何交回generator的执行权:
            a、回调函数。将异步包装成thunk函数,在回调函数中交回执行权。
            b、promise对象。将异步操作包装成promise对象,用then 方法交回执行权。
        co模块是将两种自动执行器包装成了一个模块,使用co的前提条件是,yield命令后面只能是thunk函数活着promise对象。
 
    16.4、async函数(属于es7)
        async函数:
            a、内置执行器;
            b、更好的语义;
            c、更广的适应性,async函数的await命令后面可以使promise对象和原始类型值;
            d、返回值为promise对象。
 
十七、Class
    17.1、基本语法
        定义类:
            class Point {
                constructor(x, y) {
                    this.x = x;
                    this.y = y;
                }
 
                toString() {
                    return ‘(‘ + this.x + ‘, ‘ + this.y + ‘)’;
                }
            }
    类的数据类型就是函数,类本身就指向构造函数。
    类的内部定义的所有方法都是不可枚举的。
    不存在变量提升。
 
    17.2、class的继承
        class之间通过extends关键字实现继承;通过super方法,指向父类的this对象。
        class ColorPoint extends Point {
            constructor(x, y, color) {
                super(x, y); //调用父类的constructor(x, y)
                this.color = color;            
            }
        }
    es5的继承实质上是先创造子类的实例对象this,然后再将父类的方法添加到this上(parent.apply(this));
    es6的继承实质上是先创建父类的实例对象this(调用super方法),然后再用子类的构造函数修改this。
    类的prototype属性和__proto__属性:
        a、子类的__proto__属性表示构造函数的继承,指向父类;
        b、子类的prototype的__proto__属性表示方法的继承,指向父类的prototype属性。
    extends的继承目标:
        只要具有prototype属性,就能被继承。
        object.getPrototypeOf()方法从子类上获取父类。
        super关键字代表父类的实例。
 
    17.3、原生构造函数的继承
        es5无法继承,es6可以。
 
    17.4、class的取值函数(getter)和存值函数(setter)
        与es5一样,在class内部可以使用get和set关键字对某个属性设置存值函数和取值函数,拦截该属性的存取行为。
 
    17.5、class的generator方法
        class Foo {
            constructor(…args) {
                this.args = args;
            }
            *[Symbol.iterator]() {
                for (let arg of this.args) {
                    yield arg;
                }
            }
        }
    
        for (let x of new Foo(‘hello’, ‘world’)) {
            console.log(‘x');
        }
 
        // hello //world
 
    17.6、class的静态方法
        定义:在一个方法上加static关键字,就表示该方法不会被实例继承,而是直接通过类调用,成为“静态方法”。
        通过使用extends,可以让实例继承。
 
    17.7、class的静态属性
        定义:指class本身的属性,而不是定义在实例对象(this)上的属性。
 
    17.8、new.target属性
        new是从构造函数生成实例的命令。该属性可以确定构造函数是怎么调用的。
        function Person(name) {
            if (new.target === Person) {
                this.name = name;
            } else {
                throw new Error('必须使用new生成实例’);
            }
        }
        var person = new Person(‘hit') //正确
        var notAPerson = Person.call(person, ‘张三’); // 报错
 
    17.9、mixin模式的实现
        定义:将多个类的接口“混入”另一个类:
        
十八、修饰器 (ES7 但babel支持)
    18.1、类的修饰器
        @testable
        class MyTestableClass {}
        其中的@testable为修饰器,修改了类的行为,增加了一个静态属性。
 
    18.2、方法的修饰
        class Person {
            @readonly
            name() {
                return `${this.first} ${this.last}`
            }
        }
        修饰器函数共接受3个参数,修饰的目标对象;修饰的属性名;属性的描述对象。
        function readonly(target, name, descriptor) {
            descriptor.writable = false;
            return descriptor;
        }
 
        Object.definePrototype(Person.prototype, ’name’, descriptor);
 
    18.3、为何修饰器不能用于函数
        修饰器职能用于类及类的方法,因为其存在函数提升。
 
    18.4、core-decorators.js
        其是一个第三方模块,提供了几个常见的修饰器。
        a、@autobind 使得方法中的this对象绑定原始对象。
        b、@readonly使得属性或者方法不可写;
        c、@override检查子类方法是否正确覆盖父类的同名方法;
        d、@deprecate在控制台显示一条警告,表示该方法将废除;
        e、@suppressWarnings 修饰器抑制decorated修饰器导致的console.warn调用。
 
    18.5、使用修饰器实现自动发布事件
        “发布/订阅”库postal.js
 
    18.6、mixin
        在修饰器的基础上可以实现mixin模式,就是对象继承的一种替代方案,在对象中混入另一个对象的方法。
 
    18.7、trait
        效果与mixin类似,但提供更多的功能,比如防止同名方法的冲突、排除混入某些方法、为混入的方法起别名等。第三方模块:traits-decorator。
 
十九、module
    ES6的class只是面向对象编程的语法汤,升级了ES5构造函数的原型链继承的写法,并没有解决模块化问题。
    commonjs模块是对象,输入时必须查找对象属性,其实质是整体加载模块,然后使用方法,这种为“运行时加载”。
    es6模块不是对象,而是通过export命令显示的制定输出的代码,输入时采用静态命令的形式。
    import{ start, exists, readFile} from ‘fs’;
    以上实质是从fs模块加载3个方法,其他方法不加载。这种加载称为“编译时加载”
    效率比commonjs高。
    ES6模块化的其他优点:
        a、不再需要UMD模块格式;
        b、将来浏览器的新API可以用模块格式提供,不再需要做成全局变量或者navigator对象的属性;
        c、不再需要对象作为命名空间,未来这些功能可通过模块实现。
    19.1、严格模式 [lottery插件完成后做详细了解]
        模块化自动采用严格模式,限制如下:
            a、变量必须声明后使用;
            b、函数的参数不能有同名属性,否则报错;
            c、不能使用with语句;
            d、不能对只读属性赋值,负责报错;
            e、不能使用前缀0表示八进制,否则报错;
            f、不能删除不可删除的属性,否则报错;
            g、不能删除变量(delete prop),会报错,职能删除属性(delete global[prop]);
            h、eval不会再外层作用域引入变量;
            i、eval和arguments不能被重新赋值;
            j、arguments不会自动反映函数参数的变化;
            k、不能使用arguments.callee;
            l、不能使用arguments.caller;
            m、禁止this指向全局变量;
            n、不能使用fn.caller和fn.arguments获取函数调用的堆栈;
            o、增加保留字段(protected、static和interface)。
 
    19.2、export命令
        模块功能主要由两个命令构成:export和import;export用于规定模块的对外接口;import命令用于输入其他模块提供的功能。
        // profile.js
        export { f1 as firstName, lastName, year};
 
    19.3、import命令
        import {firstName as f1, lastName, year} from ‘./profile’;
 
    19.4、模块的整体加载
        除了指定加载某个输出值,还可以使用整体加载,即用(*)指定一个对象,所有输出值都加载在这个对象上。
        import * as circle from ‘./circle’。
 
    19.5、module命令
        module可取代import命令,达到整体输入模块的作用。
        module circle from ‘./circle’。
 
    19.6、export default命令
        export default function() {};
        import cc32 from ‘crc32’;
    vs
        export function cc32() {};
        import {crc32} from ‘crc32’;
        留意大括号的区别(“{}”)。
 
    19.7、模块的继承
        export * from ‘circle’
        表示输出circle模块的所有属性和方法。
 
    19.8、ES6模块加载的实质
        ES6模块加载机制与commonjs模块完全不同。commons模块输出的是一个值的拷贝,而ES6模块输出的是值的引用。
 
    19.9、循环加载
        commonjs模块的加载原理:加载时执行,即代码在require 时就会全部执行;一旦出现“循环加载”,就只输出已经执行的部分,还未执行的部分不输出。
        ES6模块是动态引用,遇到模块加载命令import时不会去执行模块,只是生成饮用,开发者自己保证取值时能够真正取到值。
 
    19.10、ES6模块的转码
        除babel可以转外,一下两种方法也可以:
        a、ES6 module transpiler
        b、systemJS 
 
二十、编程风格[可参阅jscs.info]
    20.1、块级作用域
        let 取代 var;
        全局常量和线程安全:建议使用const而非let;
 
    20.2、字符串
        一律使用单引号或者反引号;const b = `foo${a}bar`;
 
    20.3、解构赋值
        数组成员对变量赋值,优先解构赋值。
 
    20.4、对象
        a、单行定义的对象,最后一个成员不以逗号结尾。多行定义的对象需要。
        b、对象尽量静态化,一旦定义,就不得随意添加新的属性。
            const a = {x: null};
            a.x = 3;
        c、如果对象属性名是动态的,在创建时,使用属性表达式定义。
            const obj = {
                id: 5,
                [getKey(‘enabled’)]: true
            }
        d、对象的属性和方法尽量采用简洁表达法,易于描述和书写:
            const atom = {
                ref, //ref: ref
                addValue(value) {
                    return atom.value + value;
                }
            }
 
    20.5、数组
        使用扩展运算符(...)复制数组。
        const itemsCopy = […list];
 
    20.6、函数
        a、立即执行函数使用箭头函数
            (() => {
                console.log(‘Welecome to the Internet.');
            })();
        b、使用函数表达式的场合,使用箭头函数
            [1, 2, 3].map([x] => {
                return x*x;
            })
        c、箭头函数代替Function.prototype.bind,不应再用self/_this/that绑定this.
            const boundMethod = (…params) => method.apply(this, params);
        d、简单的、单行的、不会复用的函数,建议采用箭头函数。
        e、所有配置项都应该集中在一个对象,放在最后一个参数,布尔值不可以直接作为参数:
            function divide(a, b, {option = false} = {})
        f、不再函数体内使用arguments变量,使用(…)代替:
            function all(…args) {
                return args.join('');
            }
        g、默认值语法设置函数参数的默认值:
            function handle(opts = {}){}
 
    20.7、map结构
        注意区分object和map,如果只是需要key:value的数据结构,则使用map。
 
    20.8、class    
        a、用class取代需要prototype的操作。
        b、使用extends实现继承
 
    20.9、模块
        a、module语法是javascript模块的标准写法,使用import取代require;
        b、使用export取代module.exports;
        c、export default不要与普通export同时使用;
        d、不要再模块输入中使用通配符*;
 
    20.10、eslint的使用
        其是一个语法规则和代码风格检查工具,可以确保语法正确、风格统一。        
原文地址:https://www.cnblogs.com/hity-tt/p/6511019.html