0%

es6总结

1.5万字概括ES6全部特性
ECMAScript 6入门

解构赋值

应用:

  • 交换变量值:[x, y] = [y, x]
  • 返回函数多个值:const [x, y, z] = Func()
  • 定义函数参数:Func([1, 2])
  • 提取JSON数据:const { name, version } = packageJson
  • 定义函数参数默认值:function Func({ x = 1, y = 2 } = {}) {}
  • 遍历Map结构:for (let [k, v] of Map) {}
  • 输入模块指定属性和方法:const { readFile, writeFile } = require("fs")

字符串扩展

  • Unicode表示法:大括号包含表示Unicode字符(\u{0xXX}或\u{0XXX})
  • 字符串遍历:可通过for-of遍历字符串
    1
    2
    3
    for(let a of 'abc'){
    console.log(a);
    }
  • 字符串模板:可单行可多行可插入变量的增强版字符串
  • String.raw():返回把字符串所有变量替换且对斜杠进行转义的结果
  • String.fromCodePoint():返回码点对应字符
  • codePointAt():返回字符对应码点(String.fromCodePoint()的逆操作)
  • repeat():把字符串重复n次,返回新字符串
  • matchAll():返回正则表达式在字符串的所有匹配
  • includes():是否存在指定字符串
  • startsWith():是否存在字符串头部指定字符串
  • endsWith():是否存在字符串尾部指定字符串
  • *以上方法均用于4个字节存储的Unicode字符上**

数值扩展

  • 二进制表示法:0b或0B开头表示二进制(0bXX或0BXX)
  • 八进制表示法:0o或0O开头表示二进制(0oXX或0OXX)
  • Number.parseInt():返回转换值的整数部分
  • Number.parseFloat():返回转换值的浮点数部分
  • Number.isFinite():是否为有限数值
  • Number.isNaN():是否为NaN
  • Number.isInteger():是否为整数
  • Math.trunc():返回数值整数部分
  • Math.sign():返回数值类型(正数1、负数-1、零0)

对象扩展

  • 简洁表示法:直接写入变量和函数作为对象的属性和方法
    1
    2
    3
    4
    { 
    prop,
    method() {}
    }
  • 属性名表达式:字面量定义对象时使用[]定义键
    1
    2
    3
    4
    5
    6
    7
    // 不能与上面的特性同时使用
    let foo = 'bar';
    {
    [foo]: 'foo',
    // 这样是不行的
    [foo]
    }
  • 方法的name属性:返回方法函数名
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    // 如果是get和set则不能直接取到name,需要通过描述符来访问
    const obj = {
    get foo() {},
    set foo(x) {}
    };

    obj.foo.name
    // TypeError: Cannot read property 'name' of undefined

    const descriptor = Object.getOwnPropertyDescriptor(obj, 'foo');
    // 这个方法会返回一个对象里面的内容如下
    /**
    {
    value: 1 // descriptor没有这个值,以get代替
    writable: true // descriptor没有这个值,以set代替
    enumerable: true
    configurable: true
    }
    */

    descriptor.get.name // "get foo"
    descriptor.set.name // "set foo"
    // 通过new Function创建的函数
    (new Function()).name // "anonymous"
    // bind函数返回的函数
    var doSomething = function() {
    // ...
    };
    doSomething.bind().name // "bound doSomething"
  • 属性的可枚举性和遍历:描述对象的enumerable
  • super关键字:指向当前对象的原型对象(只能用在对象的简写方法中method() {})
  • Object.is():对比两值是否相等
  • Object.assign():合并对象(浅拷贝),返回原对象
  • Object.getPrototypeOf():返回对象的原型对象
  • Object.setPrototypeOf():设置对象的原型对象
  • __proto__:返回或设置对象的原型对象

属性遍历

  • 描述:自身、可继承、可枚举、非枚举、Symbol
  • 遍历
    for-in:遍历对象自身可继承可枚举属性
    Object.keys():返回对象自身可枚举属性的键组成的数组
    Object.getOwnPropertyNames():返回对象自身可继承可枚举非枚举属性的键组成的数组
    Object.getOwnPropertySymbols():返回对象Symbol属性的键组成的数组
    Reflect.ownKeys():返回对象自身可继承可枚举非枚举Symbol属性的键组成的数组
  • 规则
    首先遍历所有数值键,按照数值升序排列
    其次遍历所有字符串键,按照加入时间升序排列
    最后遍历所有Symbol键,按照加入时间升序排列

数组扩展

  • 扩展运算符(…):转换数组为用逗号分隔的参数序列([...arr],相当于rest/spread参数的逆运算)

  • Array.from():转换具有Iterator接口的数据结构为真正数组,返回新数组

  • 类数组对象:包含length的对象、Arguments对象、NodeList对象

  • 可遍历对象:String、Set结构、Map结构、Generator函数

  • Array.of():转换一组值为真正数组,返回新数组

  • copyWithin():把指定位置的成员复制到其他位置,返回原数组

  • find():返回第一个符合条件的成员

  • findIndex():返回第一个符合条件的成员索引值

  • fill():根据指定值填充整个数组,返回原数组

  • keys():返回以索引值为遍历器的对象

  • values():返回以属性值为遍历器的对象

  • entries():返回以索引值和属性值为遍历器的对象,[0, 1]

  • 数组空位:ES6明确将数组空位转为undefined(空位处理规不一,建议避免出现,chrome使用empty处理)

扩展应用

  • 克隆数组:const arr = [...arr1](浅克隆)
  • 合并数组:const arr = [...arr1, ...arr2]
  • 拼接数组:arr.push(...arr1)
  • 代替apply:Math.max.apply(null, [x, y]) => Math.max(...[x, y])
  • 转换字符串为数组:[..."hello"]
  • 转换类数组对象为数组:[...Arguments, ...NodeList]
  • 转换可遍历对象为数组:[...String, ...Set, ...Map, ...Generator]
  • 与数组解构赋值结合:const [x, ...rest/spread] = [1, 2, 3]
  • 计算Unicode字符长度:Array.from("hello").length => [..."hello"].length

重点难点

  • 使用keys()、values()、entries()返回的遍历器对象,可用for-of自动遍历或next()手动遍历
  • 扩展运算符和Array.from()区别
    扩展运算符调用的是Symbol.iterator接口,Array.from对于具有length属性的数据结构即可
    1
    2
    3
    let  obj = {length: 3};
    Array.from(obj);// 可以转换
    [...obj]// 会报错

函数扩展

  • 参数默认值:为函数参数指定默认值
    • 形式:function Func(x = 1, y = 2) {}
    • 参数赋值:惰性求值(函数调用后才求值)
    • 参数位置:尾参数
    • 参数作用域:函数作用域
    • 声明方式:默认声明,不能用const或let再次声明
    • length:返回没有指定默认值的参数个数
    • 与解构赋值默认值结合:function Func({ x = 1, y = 2 } = {}) {}
    • 应用
      指定某个参数不得省略,省略即抛出错误:function Func(x = throwMissing()) {}
      将参数默认值设为undefined,表明此参数可省略:Func(undefined, 1)
  • rest/spread参数(…):返回函数多余参数
    形式:以数组的形式存在,之后不能再有其他参数
    作用:代替Arguments对象
    length:返回没有指定默认值的参数个数但不包括rest/spread参数
  • 严格模式:在严格条件下运行JS
    应用:只要函数参数使用默认值、解构赋值、扩展运算符,那么函数内部就不能显式设定为严格模式
  • name属性:返回函数的函数名
    • 将匿名函数赋值给变量:空字符串(ES5)、变量名(ES6)
    • 将具名函数赋值给变量:函数名(ES5和ES6)
    • bind返回的函数:bound 函数名(ES5和ES6)
    • Function构造函数返回的函数实例:anonymous(ES5和ES6)
  • 箭头函数(=>):函数简写
    • 无参数:() => {}
    • 单个参数:x => {}
    • 多个参数:(x, y) => {}
    • 解构参数:({x, y}) => {}
    • 嵌套使用:部署管道机制
      1
      2
      3
      4
      5
      6
      7
      8
      9
      // 返回一个函数接受val参数,作为数组的reduce的第一个参数,也就是a,然后在调用传入的第一个参数的时候就会将a作为参数
      const pipeline = (...funcs) =>
      val => funcs.reduce((a, b) => b(a), val);

      const plus1 = a => a + 1;
      const mult2 = a => a * 2;
      const addThenMult = pipeline(plus1, mult2);

      addThenMult(5)
    • 注意点
      • this指向固定化
        并非因为内部有绑定this的机制,而是根本没有自己的this,导致内部的this就是外层代码块的this
        因为没有this,因此不能用作构造函数
      • 不能使用arguments对象
      • 不能使用yield命令,不能做Generator函数
  • 尾调用优化:只保留内层函数的调用帧(暂时不了解)
    • 详情见尾调用优化
    • 尾调用
      • 定义:某个函数的最后一步是调用另一个函数
      • 形式:function f(x) { return g(x); }
    • 尾递归
      • 定义:函数尾调用自身
      • 作用:只要使用尾递归就不会发生栈溢出,相对节省内存
      • 实现:把所有用到的内部变量改写成函数的参数并使用参数默认值

箭头函数误区

  • 函数体内的this是定义时所在的对象而不是使用时所在的对象
  • 可让this指向固定化,这种特性很有利于封装回调函数
  • 不可当作构造函数,因此箭头函数不可使用new命令
  • 不可使用yield命令,因此箭头函数不能用作Generator函数
  • 不可使用Arguments对象,此对象在函数体内不存在(可用rest/spread参数代替)
  • 不适用场合
    • 定义对象方法
      1
      2
      3
      4
      5
      6
      const cat = {
      lives: 9,
      jumps: () => {
      this.lives--;
      }
      }
      对象不会构成单独的作用域,所以this会被绑定到全局上
    • 动态this
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      118
      119
      120
      121
      122
      123
      124
      125
      126
      127
      128
      129
      130
      131
      132
      133
      134
      135
      136
      137
      138
      139
      140
      141
      142
      143
      144
      145
      146
      147
      148
      149
      150
      151
      152
      153
      154
      155
      156
      157
      158
      159
      160
      161
      162
      163
      164
      165
      166
      167
      168
      169
      170
      171
      172
      173
      174
      175
      176
      177
      178
      179
      180
      181
      182
      183
      184
      185
      186
      187
      188
      189
      190
      191
      192
      193
      194
      195
      196
      197
      198
      199
      200
      201
      202
      203
      204
      205
      206
      207
      208
      209
      210
      211
      212
      213
      214
      215
      216
      217
      218
      219
      220
      221
            var button = document.getElementById('press');
      button.addEventListener('click', () => {
      this.classList.toggle('on');
      });
      ```返回对象时必须在对象外面加上括号

      - - -
      # Symbol
      * 定义:独一无二的值
      * 声明:`const set = Symbol(str)`
      * 入参:字符串(可选)
      * 方法
      * `Symbol()`:创建以参数作为描述的Symbol值(不登记在全局环境)
      * `Symbol.for()`:创建以参数作为描述的Symbol值,如存在此参数则返回原有的Symbol值(先搜索后创建,登记在全局环境)
      * `Symbol.keyFor()`:返回已登记的Symbol值的描述(只能返回Symbol.for()的key)
      * `Object.getOwnPropertySymbols()`:返回对象中所有用作属性名的Symbol值的数组
      * 内置
      * `Symbol.hasInstance`:指向一个内部方法,当其他对象使用instanceof运算符判断是否为此对象的实例时会调用此方法
      * `Symbol.isConcatSpreadable`:指向一个布尔,定义对象用于Array.prototype.concat()时是否可展开
      * `Symbol.species`:指向一个构造函数,当实例对象使用自身构造函数时会调用指定的构造函数
      * `Symbol.match`:指向一个函数,当实例对象被String.prototype.match()调用时会重新定义match()的行为
      * `Symbol.replace`:指向一个函数,当实例对象被String.prototype.replace()调用时会重新定义replace()的行为
      * `Symbol.search`:指向一个函数,当实例对象被String.prototype.search()调用时会重新定义search()的行为
      * `Symbol.split`:指向一个函数,当实例对象被String.prototype.split()调用时会重新定义split()的行为
      * `Symbol.iterator`:指向一个默认遍历器方法,当实例对象执行for-of时会调用指定的默认遍历器
      * `Symbol.toPrimitive`:指向一个函数,当实例对象被转为原始类型的值时会返回此对象对应的原始类型值
      * `Symbol.toStringTag`:指向一个函数,当实例对象被Object.prototype.toString()调用时其返回值会出现在toString()返回的字符串之中表示对象的类型
      * `Symbol.unscopables`:指向一个对象,指定使用with时哪些属性会被with环境排除

      ## 数据类型
      * Undefined
      * Null
      * String
      * Number
      * Boolean
      * Object(包含Array、Function、Date、RegExp、Error)
      * Symbol

      - - -
      # Set
      * 定义:类似于数组的数据结构,成员值都是唯一且没有重复的值
      * 声明:`const set = new Set(arr)`
      * 入参:具有Iterator接口的数据结构
      * 属性
      * constructor:构造函数,返回Set
      * size:返回实例成员总数
      * 方法
      * `add()`:添加值,返回实例
      * `delete()`:删除值,返回布尔
      * `has()`:检查值,返回布尔
      * `clear()`:清除所有成员
      * `keys()`:返回以属性值为遍历器的对象
      * `values()`:返回以属性值为遍历器的对象
      * `entries()`:返回以属性值和属性值为遍历器的对象
      * `forEach()`:使用回调函数遍历每个成员

      ## 应用场景
      * 去重字符串:`[...new Set(str)].join("")`
      * 去重数组:`[...new Set(arr)]或Array.from(new Set(arr))`
      * 集合数组
      * 声明:`const a = new Set(arr1)、const b = new Set(arr2)`
      * 并集:`new Set([...a, ...b])`
      * 交集:`new Set([...a].filter(v => b.has(v)))`
      * 差集:`new Set([...a].filter(v => !b.has(v)))`
      * 映射集合
      * 声明:`let set = new Set(arr)`
      * 映射:`set = new Set([...set].map(v => v * 2))或set = new Set(Array.from(set, v => v * 2))`

      ## 重点难点
      * 遍历顺序:插入顺序
      * 没有键只有值,可认为键和值两值相等
      * 添加多个NaN时,只会存在一个NaN
      * 添加相同的对象时,会认为是不同的对象
      * 添加值时不会发生类型转换(5 !== "5")
      * keys()和values()的行为完全一致,entries()返回的遍历器同时包括键和值且两值相等

      - - -
      # Map
      * 定义:类似于对象的数据结构,成员键可以是任何类型的值
      * 声明:const set = new Map(arr)
      * 入参:具有Iterator接口且每个成员都是一个双元素数组的数据结构
      * 属性
      * constructor:构造函数,返回Map
      * size:返回实例成员总数
      * 方法
      * get():返回键值对
      * set():添加键值对,返回实例
      * delete():删除键值对,返回布尔
      * has():检查键值对,返回布尔
      * clear():清除所有成员
      * keys():返回以键为遍历器的对象
      * values():返回以值为遍历器的对象
      * entries():返回以键和值为遍历器的对象
      * forEach():使用回调函数遍历每个成员
      * 重点难点
      * 遍历顺序:插入顺序
      * 对同一个键多次赋值,后面的值将覆盖前面的值
      * 对同一个对象的引用,被视为一个键
      * 对同样值的两个实例,被视为两个键
      * 键跟内存地址绑定,只要内存地址不一样就视为两个键
      * 添加多个以NaN作为键时,只会存在一个以NaN作为键的值
      * Object结构提供字符串—值的对应,Map结构提供值—值的对应

      - - -
      # Proxy
      * 定义:修改某些操作的默认行为
      * 声明:`const proxy = new Proxy(target, handler)`
      * 入参
      * target:拦截的目标对象
      * handler:定制拦截行为
      * 方法
      * `Proxy.revocable()`:返回可取消的Proxy实例(返回{ proxy, revoke },通过revoke()取消代理)
      * 拦截方式
      * `get()`:拦截对象属性读取
      * `set()`:拦截对象属性设置,返回布尔
      * `has()`:拦截对象属性检查k in obj,返回布尔
      * `deleteProperty()`:拦截对象属性删除delete obj[k],返回布尔
      * `defineProperty()`:拦截对象属性定义Object.defineProperty()、Object.defineProperties(),返回布尔
      * `ownKeys()`:拦截对象属性遍历for-in、Object.keys()、Object.getOwnPropertyNames()、Object.getOwnPropertySymbols(),返回数组
      * `getOwnPropertyDescriptor()`:拦截对象属性描述读取Object.getOwnPropertyDescriptor(),返回对象
      * `getPrototypeOf()`:拦截对象原型读取instanceof、Object.getPrototypeOf()、Object.prototype.__proto__、Object.prototype.isPrototypeOf()、Reflect.getPrototypeOf(),返回对象
      * `setPrototypeOf()`:拦截对象原型设置Object.setPrototypeOf(),返回布尔
      * `isExtensible()`:拦截对象是否可扩展读取Object.isExtensible(),返回布尔
      * `preventExtensions()`:拦截对象不可扩展设置Object.preventExtensions(),返回布尔
      * `apply()`:拦截Proxy实例作为函数调用proxy()、proxy.apply()、proxy.call()
      * `construct()`:拦截Proxy实例作为构造函数调用new proxy()
      * 应用场景
      * `Proxy.revocable()`:不允许直接访问对象,必须通过代理访问,一旦访问结束就收回代理权不允许再次访问
      * `get()`:读取未知属性报错、读取数组负数索引的值、封装链式操作、生成DOM嵌套节点
      * `set()`:数据绑定(Vue数据绑定实现原理)、确保属性值设置符合要求、防止内部属性被外部读写
      * `has()`:隐藏内部属性不被发现、排除不符合属性条件的对象
      * `deleteProperty()`:保护内部属性不被删除
      * `defineProperty()`:阻止属性被外部定义
      * `ownKeys()`:保护内部属性不被遍历
      * 重点难点
      * 要使Proxy起作用,必须针对实例进行操作,而不是针对目标对象进行操作
      * 没有设置任何拦截时,等同于直接通向原对象
      * 属性被定义为不可读写/扩展/配置/枚举时,使用拦截方法会报错
      * 代理下的目标对象,内部this指向Proxy代理

      - - -
      # Class
      * 定义:对一类具有共同特征的事物的抽象(构造函数语法糖)
      * 原理:类本身指向构造函数,所有方法定义在prototype上,可看作构造函数的另一种写法(Class === Class.prototype.constructor)
      * 方法和关键字
      * `constructor()`:构造函数,new命令生成实例时自动调用
      * `extends`:继承父类
      * `super`:新建父类的this
      * `static`:定义静态属性方法
      * `get`:取值函数,拦截属性的取值行为
      * `set`:存值函数,拦截属性的存值行为
      * 属性
      * `__proto__`:构造函数的继承(总是指向父类)
      * `__proto__.__proto__`:子类的原型的原型,即父类的原型(总是指向父类的__proto__)
      * `prototype.__proto__`:属性方法的继承(总是指向父类的prototype)
      * 静态属性:定义类完成后赋值属性,该属性不会被实例继承,只能通过类来调用
      * 静态方法:使用static定义方法,该方法不会被实例继承,只能通过类来调用(方法中的this指向类,而不是实例)
      * 继承
      * 实质
      * ES5实质:先创造子类实例的this,再将父类的属性方法添加到this上(Parent.apply(this))
      * ES6实质:先将父类实例的属性方法加到this上(调用super()),再用子类构造函数修改this
      * super
      * 作为函数调用:只能在构造函数中调用super(),内部this指向继承的当前子类(super()调用后才可在构造函数中使用this)
      * 作为对象调用:在普通方法中指向父类的原型对象,在静态方法中指向父类
      * 显示定义:使用constructor() { super(); }定义继承父类,没有书写则显示定义
      * 子类继承父类:子类使用父类的属性方法时,必须在构造函数中调用super(),否则得不到父类的this
      * 父类静态属性方法可被子类继承
      * 子类继承父类后,可从super上调用父类静态属性方法
      * 实例:类相当于实例的原型,所有在类中定义的属性方法都会被实例继承
      * 显式指定属性方法:使用this指定到自身上(使用Class.hasOwnProperty()可检测到)
      * 隐式指定属性方法:直接声明定义在对象原型上(使用Class.__proto__.hasOwnProperty()可检测到)
      * 表达式
      * 类表达式:const Class = class {}
      * name属性:返回紧跟class后的类名
      * 属性表达式:[prop]
      * Generator方法:* mothod() {}
      * Async方法:async mothod() {}
      * this指向:解构实例属性或方法时会报错
      * 绑定thisthis.mothod = this.mothod.bind(this)
      * 箭头函数:this.mothod = () => this.mothod()
      * 属性定义位置
      * 定义在构造函数中并使用this指向
      * 定义在类最顶层
      * new.target:确定构造函数是如何调用

      ## 原生构造函数
      * String()
      * Number()
      * Boolean()
      * Array()
      * Object()
      * Function()
      * Date()
      * RegExp()
      * Error()

      ## 重点难点
      * 在实例上调用方法,实质是调用原型上的方法
      * `Object.assign()`可方便地一次向类添加多个方法`(Object.assign(Class.prototype, { ... }))`
      * 类内部所有定义的方法是不可枚举的(non-enumerable)
      * 构造函数默认返回实例对象(this),可指定返回另一个对象
      * 取值函数和存值函数设置在属性的Descriptor对象上
      * 类不存在变量提升
      * 利用`new.target === Class`写出不能独立使用必须继承后才能使用的类
      * 子类继承父类后,this指向子类实例,通过super对某个属性赋值,赋值的属性会变成子类实例的属性
      * 使用super时,必须显式指定是作为函数还是作为对象使用
      * extends不仅可继承类还可继承原生的构造函数

      ## 私有属性方法
      ```js
      const name = Symbol("name");
      const print = Symbol("print");
      class Person {
      constructor(age) {
      this[name] = "Bruce";
      this.age = age;
      }
      [print]() {
      console.log(`${this[name]} is ${this.age} years old`);
      }
      }

继承混合类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function CopyProperties(target, source) {
for (const key of Reflect.ownKeys(source)) {
if (key !== "constructor" && key !== "prototype" && key !== "name") {
const desc = Object.getOwnPropertyDescriptor(source, key);
Object.defineProperty(target, key, desc);
}
}
}
function MixClass(...mixins) {
class Mix {
constructor() {
for (const mixin of mixins) {
CopyProperties(this, new mixin());
}
}
}
for (const mixin of mixins) {
CopyProperties(Mix, mixin);
CopyProperties(Mix.prototype, mixin.prototype);
}
return Mix;
}
class Student extends MixClass(Person, Kid) {}