• ECMAScript6


    ECMAScript6

    ECMAScript 6 (以下简称 ES6 )是 JavaScript 语言的下一代标准,己于 2015 月正式发布。
    它的目标是使 JavaScript 语言可以用于编写复杂的大型应用程序,成为企业级开发语言

    语法提案的批准流程

    任何人都可以向标准委员会(又称 TC39 委员会)提案,要求修改语言标准。
    一种新的语法从提案到变成正式标准,需要经历五个阶段。每个阶段的变动都要由 TC39委员会批准。

    • Stage 0: Strawman (展示阶段) 
    • Stage 1 : Proposal (征求意见阶段〉
    • Stage 2: Draft (草案阶段)
    • Stage 3: Candidate (候选阶段)
    • Stage 4: Finished (定案阶段)

    ECMAScript当前的所有提案都可以在 TC39 的官方网站 Github.com/tc39/ecma262 中查看。

    let和const命令

    let和const声明的变量存在暂时性死区

    1var tmp = 123
    2if (true) {
    3  tmp = 'abc' // ReferenceError
    4  let tem
    5}
    6
    7......
    8typeof x // ReferenceError
    9let x
    10
    11......
    12function bar(x = y, y = 2) {
    13  return [x , y]
    14}
    15bar() // 报错

    相关新提案

    wiki.ecmascript.org/doku.php?id=strawman:do expressions,使得块级作用域可以变为表达式,即可以返回值,办法就是在块级作用域之前加上do,使它变为 do 表达式。

    1let x = do {
    2  let t = f()
    3  t * t + l
    4}

    https://github.com/tc39/proposal-global,在语言标准的层面引入 global 作为顶层对象。也就是说,在所有环境下,global 都是存在的,都可以拿到顶层对象。

    变量的解构赋值

    默认值

    ES6 内部使用严格相等运算符===判断一个位直是否有值 所以,如果一个数组成员不严格等于 undefined ,默认位是不会生效的

    1let [x = 1] = [undefined]
    2// 1
    3
    4let [x = 1] = [null]
    5// null

    对象的解构赋值

    如果变量名与属性名不一致,必须写成下面这样。

    1var { foo : baz } = { foo'aaa'bar'bbb' }
    2baz // 'aaa'

    实际上说明,对象的解构赋值是下面形式的简写

    1let { foo: foo , bar: bar } = { foo'aaa'bar'bbb'}

    也就是说,对象的解构赋值的内部机制是先找到同名属性,然后再赋值给对应的变量。真正被赋值的是后者,而不是前者。

    1let { foo : baz } = { foo'aaa'bar'bbb'}
    2baz // 'aaa'
    3foo // error: foo is not defined
    4// 上面的代码中, foo 是匹配的模式, baz 才是变量。真正被赋值的是变量 baz ,而不是模式foo。

    demo

    1var node = {
    2  loc: {
    3    start: {
    4      line1,
    5      column5
    6    }
    7  }
    8}
    9let { loc, loc: { start } , loc: { start: { line } } } = node
    10line // 1
    11loc // Object {start: Object}
    12start // Object {line: 1, column: 5}

    上面的代码有三次解构赋值,分别是对 loc start line 三个属性的解构赋值。需要注意的是,最后一次对 line 属性的解构赋值之中,只有 line 是变量, loc start 都是模式,不是变量。

    将一个已经声明的变量用于解构赋值

    1// 错误的写法
    2let x
    3{x} = {x : 1}
    4// SyntaxError: syntax error

    上面代码的写法会报错 因为 JavaScript 引擎会将{}理解成一个代码块,从而发生语法错误。只有不将大括号写在行首,避免 JavaSript 将其解释为代码块,才能解决这个问题

    1// 正确的写法
    2let x
    3({x} = {x : 1})

    其他类型

    1const [a , b, c , d , e] = 'hello'
    2// 'h'
    3
    4let {length : len} = 'hello'
    5len // 5
    6
    7......
    8// 如果等号右边是数值和布尔值 ,则会先转为对象。
    9let {toString : s} = 123
    10s === Number.prototype.toString // true
    11let {toString: s} = true
    12s === Boolean.prototype.toString // true
    13// undefined null 无法转为对象,所以对它们进行解构赋值时都会报错。
    14let { prop: x } = undefined // TypeError
    15let { prop: y } = null // TypeError

    字符串的扩展

    方法

    1codePointAt()
    2String.fromCodePoint()
    3at()
    4normalize()
    5
    6// 处理4个字节储存的字符

    由 for … of 循环遍历字符串可以识别大于 OxFFFF 的码点

    • includes:返回布尔值,表示是否找到了参数字符串
    • starts With: 返回布尔值,表示参数字符串是否在源字符串的头部
    • ends With:返回布尔值, 表示参数字符串是否在源字符串的尾部
    • repeat 方法返回一个新字符串,表示将原字符串重复n次。
    • padStart 用于头部补全
    • padEnd 用于尾部补全

    正则的扩展

    u

    ES6 对正则表达式添加了u修饰符,含义为“Unicode 模式”,用来正确处理大于\uFFFF的Unicode 字符。也就是说,可以正确处理4个字节的 UTF-16 编码。

    1/^\uD83D/u . test ('\uD83D\uDC2A'// false
    2/^\uD83D/ .test ('\uD83D \uDC2A'// true
    3/{2}/.test(''// false
    4/{2}/u.test(''// true

    一个正确返回字符串长度的函数。

    1function codePointLength(text{
    2  var result= text.match(/[\s\S]/gu)
    3  return result ? result.length : 0
    4}
    5
    6var s = ''
    7s.length // 4
    8codePointLength(s) // 2

    y

    ES6 还为正则表达式添加了y修饰符,叫作“粘连”( sticky )修饰符

    y修饰符的设计本意就是让头部匹配^的标志在全局匹配中都有效。

    属性

    y修饰符相匹配, ES6 的正则对象多了 sticky 属性,表示是否设置了y修饰符。

    1var r = /hello\d/y
    2r.sticky // true

    ES6 为正则表达式新增了 flags 属性,会返回正则表达式的修饰符。

    1// ES5 source 属性 返回正则表达式的正文
    2// ES6 flags 属性 返回正则表达式的修饰符
    3/abc/ig.source
    4// 'abc'
    5/abc/ig.flags
    6// 'gi'

    新提案

    github.com/mathiasbynens/es-regexp-dotall-flag:引入s修饰符,使得 .可以匹配任意单个字符。

    1/foo.bar/.test ('foo\nbar'// false
    2/foo.bar/s.test ('foo\nbar'// true

    https://github.com/goyakin/es-regexp-lookbehind被提出:引入后行断言,其中 V8 引擎 4.9 版本己经支持。

    “先行断言”指的是,x只有在y前面才匹配,必须写成/x(?=y)/的形式。“先行否定断言”指的是,x只有不在y前面才匹配,必须写成 /x(?!y)/的形式
    “后行断言”正好与“先行断言”相反,x只有在y后面才匹配,必须写成/(?<=y)x/的形式。“后行否定断言”则与“先行否定断言”相反,x只有不在y后面才匹配,必须写成/(?<!y)x/的形式。

    github.com/mathiasbynens/es-regexp-unicode-property-escapes 中引入了一种新的写法:\p{ … }和\p { … },允许正则表达式匹配符合 Unicode 某种属性的所有字符。

    1const regexGreekSymbol = /\p{Script=Greek}/u
    2regexGreekSymbol.test('Π'// true
    3// 上面的代码中,\p{Script=Greek}指定匹配一个希腊文字母,所以匹配Π成功。

    “具名组匹配”(Named Capture Groups) 提案 github.com/tc39/proposal-regexpd-named-groups,其中允许为每一个组匹配指定一个名字,既便于阅读代码,又便于引用。

    1const R_ DATE = /(?<year>\d{4})-(?<month>\d{2} )-(?<day>\d{2} )/
    2const matchObj = RE_DATE.exec ('1999-1 2-31');
    3const year= matchObj.groups.year // 1999
    4const month= matchObj.groups.month // 12
    5const day= matchObj.groups.day  // 31

    如果要在正则表达式内部引用某个“具名组匹配”,可以使用\k<组名>的写法。

    数值的扩展

    方法

    1Number.isFinite() // 检查一个数值是否为有限的
    2Number.isNaN() // 检查一个值是否为 NaN
    3
    4// parselnt,parseFloat移植到了 Number 对象上面
    5Number.parselnt()
    6Number.parseFloat()
    7
    8Nurnber islnteger() // 判断一个值是否为整数
    9
    10Number.EPSILON // 浮点数计算的合理误差范围
    11
    12// js安全整数
    13Number.MAX_SAFE_INTEGER // Math.pow(2, 53) - 1
    14Number.MIN_SAFE_INTEGER // -Number.MAX SAFE INTEGER
    15Number.isSafeinteger() // 用来判断一个整数是否落在安全范围之内

    Math扩展

    • Math.trunc 方法用于去除一个数的小数部分,返回整数部分。
    • Math.sign 方法用来判断一个数到底是正数、负数,还是零。
    • Math.cbrt 方法用于计算一个数的立方根。
    • Math.clz32 方法返回一个数的 32 位无符号整数形式有多少个前导0。
    • Math.imul 方法返回两个数以 32 位带符号整数形式相乘的结果,返回的也是 32 位的带符号整数。
    • Math.fround 方法返回一个数的单精度浮点数形式
    • Math.hypot 方法返回所有参数的平方和的平方根
    • Math.expml(x) 返回 e^x-1
    • Math.loglp(x) 方法返回 ln(l+x)
    • Math.loglO(x) 返回以 10 为底的 x 的对数
    • Math.log2(x) 返回以 2 为底的 x 的对数
    • Math.sinh(x) 返回x的双曲正弦( hyperbolic sine)
    • Math.cosh(x) 返回x的双曲余弦( hyperbolic cosine)
    • Math.tanh(x) 返回x的双曲正切( hyperbolic tangent)
    • Math.asinh(x) 返回x的反双曲正弦( inverse hyperbolic sine)
    • Math.acosh(x) 返回x的反双曲余弦( inverse hyperbolic cosine)
    • Math.atanh(x) 返回x的反双曲正切( inverse hyperbolic tangent)
    • Math.signbit() 方法判断一个数的符号位是否己经设置。

    ES2016 新增了一个指数运算符**

    12 ** 2 // 4
    22 ** 3 // 8
    3
    4a **= 2
    5// 等同于 a = a * a

    注意: 在 V8 引擎中,指数运算符与 Math.pow 的实现不相同,对于特别大的运算结果,两者会有细微的差异

    新提案

    提案github.com/tc39/proposal-bigint 其中引入了新的数据类型 Integer (整数)来表示整数,没有位数的限制,任何位数的整数都可以精确表示。用以提升js Math.MAX_SAFE_INTEGER 的上限

    1typeof 123n
    2// 'bigint'

    函数的扩展

    尾调用

    尾调用(TailCall)是函数式编程一个重要概念,是指某个函数的最后一步是调用另一个函数
    函数调用自身称为递归。如果尾调用自身就称为尾递归。

    作“尾调用优化”,即只保留内层函数的调用帧,如果所有函数都是尾调用,那么完全可以做到每次执行时调用帧只有一项,这将大大节省内存。这就是“尾调用优化”的意义。

    提案

    github.com/zenparsing/es-function-bind 函数绑定运算符是井排的双冒号::,双冒号左边是一个对象,右边是一个函数,运算符会自动将左边的对象作为上下文环境(即 this 对象〉绑定到右边的函数上。

    1foo::bar
    2// 等同于
    3bar.bind(foo)
    4
    5foo::bar (...arguments)
    6// 等同于
    7bar.apply(foo, arguments)

    ES2017 中有一个提案github.com/jeffmo/es-trailing-function-commas,允许函数的最后一个参数有尾逗号.

    数组的扩展

    扩展运算符

    扩展运算符能够正确识别32位的 Unicod 字符。

    1'x'.length // 5
    2[...'x'].length // 3
    3
    4'x'.split('').reverse().join('')
    5// '\uDFB7\uD842x'
    6[...'x'].reverse().join('')
    7// 'x'

    任何 Iterator 接口的对象(参见第 15 章)都可以用扩展运算符转为真正的数组。

    1let nodeList = document.querySelectorAll('div')
    2let array = [...nodeList]

    Array.from()

    Array.from 方法用于将两类对象转为真正的数组,类似数组的对象(array-like object)和可遍历(iterable)对象,包括ES6新增的数据结 Set和Map

    Array.of()

    Array.of 方法用于将一组值转换为数组。这个方法的主要目的是弥补数组构造函数 Array() 的不足 因为参数个数的不同会导致Array()的行为有差异。

    copyWithin()

    数组实例的 copyWithin 方法会在当前数组内部将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。也就是说,使用这个方法会修改当前数组。

    1[12 , 3 , 45].copyWithin(03)
    2// [4, 5 , 3 , 4, 5]
    3
    412 , 3 , 45].copyWithin(034)
    5// [4 , 2 , 3 , 4, 5]

    find()和 findIndex()

    数组实例的find 方法用于找出第一个符合条件的数组成员。如果没有符合条件的成员,则返回 undefined;数组实例的 findindex 方法的用法与 find 方法非常类似 返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1

    fill()

    fill 方法使用给定值填充一个数组。

    entries() keys() values()

    keys()是对键名的遍历 values() 是对键值的遍历 entrie()是对键值对的遍历。

    includes()

    includes 方法返回一个布尔值,表示某个数组是否包含给定的值,与字符串的 includes 方法类似。

    另外, Map和Set 数据结构有一个 has 方法,需要注意与 includes 区分。

    • Map 结构的 has 方法是用来查找键名的,比如 Map.prototype.has(key)WeakMap prototype.has(key)Reflect has(target propertyKey)
    • Set 结构的 has 方法是用来查找值的,比如 Set.prototype.has(value)WeakSet.prototype.has(value)

    对象的扩展

    ES6 允许字面量定义对象时,把表达式放在方括号内。

    1let propKey = 'foo'
    2let obj = {
    3  [propKey]: true,
    4  ['a' + 'b']: 123,
    5  [propKey + 'c']() {
    6    return '0'
    7  }
    8}

    Object.is()

    同值相等对比

    1+0 === -0 // true
    2NaN === NaN // false
    3
    4Object.is(+0-0// false
    5Object.is(NaNNaN// true

    Object.assign()

    Object.assign 方法用于将源对象的所有可枚举属性复制到目标对象。Object.assign方法实行的是浅复制

    `proto`、 `Object.setPrototypeOf()`、`Object.getPrototypeOf()`

    操作对象原型方法

    `Object.keys()`、 `Object.values()`、 `Object.entries()`

    ES2017 中有 个提案github.com/tc39/proposal-object-values-entries,其中引入了与Object.keys 配套的 Object.values Object.entries 作为遍历一个对象的补充手段,供for ... of 循环使用。

    其他方法

    • Object.getOwnPropertyDescriptors 方法,返回指定对象所有自身
      属性(非继承属性)的描述对象。

    • 提案github.com/tc39/proposal-object-valuesentries,其中引入了“Null 传导运算符” ?.,可以简化属性读取判断。

    obj?.prop:读取对象属性
    obj?.[expr]:同上
    func?.(…args):函数或对象方法的调用
    new C?.(… args):构造函数的调用

    Symbol

    Symbol 值作为对象属性名时不能使用点运算符, Symbol 值必须放在方括号中.

    Symbol.for()、 Symbol.keyFor()

    有时,我们希望重新使用同一个 Symbol 值, Symbol.for 接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个Symbol 值,否则就新建井返回一个以该字符串为名称的Symbol 值。Symbol.keyFor 方法返回一个己登记的 Symbol 类型值的 key

    1var sl = Symbol.for('foo')
    2var s2 = Symbol.for('foo')
    3sl === s2 // true
    4......
    5var sl = Symbol.for('foo')
    6Symbol.keyFor(sl) // 'foo'
    7var s2 = Symbol('foo')
    8Symbol.keyFor(s2) // undefined

    Symbol.for 为 Symbol 登记的名字是全局环境的,可以在不同的 iframe service worker 中取到同一个值

    内置的Symbol值

    • Symbol.hasinstance 属性指向一个内部方法,对象使用 instanceof 运算符时会调用这个方法,判断该对象是否为某个构造函数的实例。
    • Symbol.isConcatSpreadable 属性等于一个布尔值,表示该对象使用
      Array.prototype.concat()时是否可以展开。
    • Symbol.species 属性指向当前对象的构造函数。创造实例时默认会调用这个方法,即使用这个属性返回的函数当作构造函数来创造新的实例对象
    • Symbol.match 属性指向一个函数,当执行 str.match(myObject)时 ,如果该属性存在,会调用它返回该方法的返回值。
    • Symbol.replace 属性指向一个方法,当对象被 String.prototype.replace方法调用时会返回该方法的返回值。
    • Symbol.search 属性指向一个方法,当对象被 String.prototype.search方法调用时会返回该方法的返回值。
    • Symbol.split 属性指向一个方法,当对象被 String.prototype.split方法调用时会返回该方法的返回值。
    • Symbol.iterator 属性指向该对象的默认遍历器方法。
    • Symbol.toPrimitive 属性指向 个方法,对象被转为原始类型的值时会调用这个方法,返回该对象对应的原始类型值。
    • Symbol.toStringTag 属性指向一个方法,在对象上调用 Object.prototype.toString方法时,如果这个属性存在,其返回值会出现在 toString 方法返回的字符串中,表示对象的类型。也就是说,这个属性可用于定制[object Object][object Array]中 object 后面的字符串。
    • Symbol.unscopables 属性指向一个对象,指定了使用 with 关键字时哪些属性会被 with 环境排除。

    Set 和 Map

    Set对象是值的集合 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。
    Map 对象保存键值对。任何值都可以作为一个键或一个值

    WeakSet 结构与 Set 类似,也是不重复的值的集合,WeakSet 的成员只能是对象,而不能是其他类型的值
    WeakSet 中的对象都是弱引用,不影响js垃圾回收机制。
    WeakMap 对象是一组键/值对的集合,其中的键是弱引用的。其键必须是对象,而值可以是任意的。
    原生的 WeakMap 持有的是每个键对象的“弱引用”,不影响js垃圾回收机制。

    Proxy和Reflect

    1. Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与proxy handlers的方法相同。 Reflect对象有4个意义:
      • 从Reflect对象上可以拿到语言内部的方法。
      • 操作对象出现报错时返回false
      • 让操作对象都变为函数式编程
      • 保持和proxy对象的方法一一对象
    2. Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。

    vue3 的核心代码

    Iterator 和 for … of

    遍历器Iterator是一种机制。它是一种接口,为各种不同的数据结构提供统一访问机制。任何数据结构,只要部署 Iterator 接口,就可以完成遍历操作。
    Iterator 接口主要供 for … of 消费。

    1let arr = ['a''b''c']
    2let iter = arr[Symbol.iterator]()
    3iter.next() // { value: 'a', done: false }
    4iter.next() // { value: 'b', done : false }
    5iter.next() // { value: 'c', done: false }
    6iter.next() // { value: undefined, done: true }

    Generator

    Generator 函数是 ES6 提供的一种异步编程解决方案。执行 Generator 函数会返回一个遍历器对象。返回的遍历器对象可以依次遍历 Generator 函数内部的每一个状态。

    1functionhelloWorldGenerator() {
    2  yield 'hello'
    3  yield 'world'
    4  return 'ending'
    5}
    6var hw = helloWorldGenerator()
    7
    8hw.next()
    9// { value: 'hello', done: false }
    10hw.next()
    11// { value: 'world', done: false }
    12hw.next()
    13// { value: 'ending', done: true }
    14hw.next()
    15// { value: undefined, done: true }
    16
    17......
    18for(let i of hw) {
    19  console.log(i)
    20}
    21// hello
    22// world

    yield 语句与 return 语句既有相似之处,又有区别。相似之处在于都能返回紧跟在语句后的表达式的值 区别在于每次遇到 yield 函数暂停执行,下一次会从该位置继续向后执行,return 语句不具备位置记忆的功能。
    yield 语句本身没有返回值,或者说总是返回 undefined, next 方法可以带有一个参数,该参数会被当作上 yield 语句的返回值

    注意:yield 表达式如果用在另一个表达式之中,必须放在圆括号里面。用作函数参数或放在赋值表达式的右边,可以不加括号。

    对象原生不具备 Iterator 口,无法用 for ... of 遍历。这时,我们
    通过 Generator 函数为它加上遍历器接口,这样就可以用 for ... of 遍历了。另一种写法是,将 Generator 函数加到对象的 Symbol.iterator 属性上。

    1functionobjectEntries () {
    2  let propKeys = Object.keys(this)
    3  for (let propKey of propKeys) {
    4    yield [propKey , this[propKey]]
    5  }
    6}
    7let jane = { first'Jane'last'Doe'}
    8jane[Symbol.iterator] = objectEntries
    9
    10for (let [key , value] of jane) {
    11  console.log(`${key}${value}`)
    12}
    13
    14// first: Jane
    15// last: Doe

    Generator.prototype.throw()

    Generator 函数返回的遍历器对象都有 throw 方法,可以在函数体外抛出错误,然后 Generator 函数体内捕获

    Generator.prototype.return()

    Generator 函数返回的遍历器对象还有一个 return 方法,可以返回给定的值,并终结 Generator 函数的遍历。

    yield*

    yield* 语句,用来在一个 Generator 函数里面执行另 Generator 函数。

    1functionfoo () {
    2  yield 'a'
    3  yield 'b'
    4}
    5
    6functionbar() {
    7  yield 'x'
    8  yield* foo()
    9  yield 'y'
    10}
    11
    12// 等同于
    13functionbar() {
    14  yield 'x'
    15  yield 'a'
    16  yield 'b'
    17  yield 'y'
    18}

    作为对象属性的 Generator 函数

    如果一个对象的属性是 Generator 函数,那么可以简写成下面的形式。

    1let obj = {
    2  * myGeneratorMethod() {
    3    // codes
    4  }
    5}

    async await

    async 函数使得异步操作变得更加方便。 async 函数就是 Generator 函数的语法糖

    demo

    1var fs = required('fs')
    2var readFile = function(fileName{
    3  return new Promise(function(resolve, reject{
    4    fs.readFile(fileName, function(error, data{
    5      if (error) return reject(error)
    6      resolve(data)
    7  })
    8})
    9// Generator
    10var gen = function* () {
    11  var fl = yield readFile ('/etc/fstab')
    12  var f2 = yield readFile ('/etc/shells')
    13  console.log(fl.toString())
    14  console.log(f2.toString())
    15}
    16// async
    17var asyncReadFile = async function() (
    18  var fl = await readFile ('/etc/fstab'
    )
    19  var f2 = await readFile ('/etc/shells')
    20  console.log(fl.toString())
    21  console.log(f2.toString())
    22}
    23

    通过比较就会发现,async 函数就是将 Generator 函数的星号*替换成 async ,将 yield替换成 await ,仅此而己。

    async 对比 Generator

    • 内置执行器
    • 更好的语义
    • 更广的使用性
    • 返回值是Promise

    Promise Generator async 异步处理对比

    1. Promise 的写法相比回调函数的写法大大改进,但是一眼看上去,代码完全是 Promise的 API (then catch 等),操作本身的语义反而不容易看出来
    2. Generator 语义比 Promise 写法更清晰。这个写法的问题在于,必须有一个任务运行器自动执行 Generator 函数,而且必须保证 yield 语句后面的表达式返回 Promise
    • async 函数的实现最简洁,最符合语义,几乎没有与语义不相关的代码。

    Class

    ES6 引入了 Class (类)这个概念作为对象的模板。通过 class 关键字可以定义类。

    类的构造方法 constructor 默认指向本身,也可指定返回另一个对象

    私有方法与私有属性

    私有方法是常见需求,但 ES6 不提供,只能通过变通方法来模拟实现。
    与私有方法一样, ES6 不支持私有属性。

    提案 github.com/tc39/proposal-classfields#private-fields 为 Class 加了私有属性。方法是在属性名之前,使用#来表示。

    1class Point {
    2  #x
    3  #square() { return this.#x ** 2 }
    4
    5  constructor(x = 0) {
    6    this.#x = +x
    7  }
    8
    9  get x() { return this.#square() }
    10  set x(value) { this.#x = +value }
    11}

    静态方法

    如果在一个方法前加上 static 关键字,就表示该方法不会被实例继承,而是直接通过类调用,称为“静态方法”。

    1class Foo {
    2  static classMethod() {
    3    return 'hello'
    4  }
    5}
    6
    7Foo.classMethod() // 'hello'
    8
    9var foo = new Foo()
    10foo.classMethod()
    11// TypeError: foo.classMethod is not a function
    12
    13// 父类的静态方法可以被子类继承。
    14class Bar extends Foo {}
    15Bar.classMethod() // 'hello'

    静态方法也可以从 super 对象上调用。Class 内部调用 new.target ,返回当前 Class

    继承

    Class 可以通过 extends 关键字实现继承,子类通过 super 调用父类的属性和方法

    1class Point {}
    2
    3class ColorPoint extends Point {
    4  constructor(x, y, color) {
    5    super(x, y)
    6    this.color = color
    7  }
    8
    9  toString() {
    10    return this.color + '' + super.toString()
    11  }

    子类必须在 constructor 方法中调用 super 方法 否则新建实例时会报错。这是因为子类没有自己的 this 对象,而是继承父类的 this 对象,然后对其进行加工。如果不调用 super 方法,子类就得不到 this 对象。如果子类没有定义 constructor 方法,那么这个方法会被默认添加。

    Object.getPrototypeOf 方法可以用来从子类上获取父类。

    Decorator 类的修饰器

    修饰器Decorator是一个函数,用来修改类的行为。修饰器不仅可以修饰类,还可以修饰类的属性。

    1@testable
    2class MyTestableClass {
    3  @readonly
    4  name() { return `${this.first}${this.last}`}
    5}
    6
    7function testable(target{
    8  target.isTestable = true
    9}
    10function readonly(target, name, descriptor{
    11  // descriptor 对象原来的值如下
    12  // {
    13  //  value: specifiedFunction,
    14  //  enumerable : false ,
    15  //  configurable: true ,
    16  //  writable : true
    17  // }
    18  descriptor.writable = false
    19  return
    20}
    21MyTestableClass.isTestable // true

    由于存在函数提升,修饰器不能用于函数。

    module

    `export`与 `import`的复合写法

    1export { foo, bar } from 'my_module'
    2// 等同于
    3import { foo, bar J from 'my_module'
    4export { foo, bar }

    ES6 模块输出的是值的引用,是编译时输出接口。

    ES6编程风格

    • let 完全可以取代 var ,因为两者语义相同,而且 let 没有副作用。

    • let const 之间,建议优先使用 const

      const 可以提醒阅读程序的人,这个变量不应该改变
      const 比较符合函数式编程思想,运算不改变值,只是新建值,而且这样也有利于将来的分布式运算
      JavaScript 编译器会对 const 进行优化,所以多使用 const 有利于提供程序的运行效率

    • 静态字符串一律使用单引号或反引号,不使用双引号。动态字符串使用反引号。

    • 使用数组成员对变量赋值时,或者函数的参数如果是对象的成员,优先使用解构赋值。

    • 单行定义的对象,最后一个成员不以逗号结尾。多行定义的对象,最后一个成员以逗号结尾

    • 使用扩展运算符复制数组,使用 Array.from 方法将类似数组的对象转为数组。

    • ,只有模拟实体对象时才使用 Object 。如果只是需要 key: value 的数据结构 ,则使用 Map 。因为 Map 有内建的遍历机制

    • 总是用 Class 取代需要 prototype 的操作。因为 class 写法更简洁,更易于理解。

    ECMA 官方标准

    规格文件 https://262.ecma-international.org/6.0/

    上述地址为ECMA国际标准组织的官方网站,其中对ES6的语法以及函数的实现都做了详尽而清晰的描述


  • 相关阅读:
    小程序 横向水平 垂直滚动
    小程序radio-group切换
    Linux系统下安装rabbitmq
    timestamp 和 datetime
    linux下部署程序,tomcat启动正常,但网页无法访问
    JSP 标签库(一)之<c:import>
    MyBaitis SQL(一)
    JSP页面url传递参数编码问题
    获取同级td的值
    解决ajax获取不到按钮的id
  • 原文地址:https://www.cnblogs.com/qinyuandong/p/15860652.html
Copyright © 2020-2023  润新知