• ECMAScript

      • 简称ES,通常看作JavaScript的标准化规范

      • 实际上JavaScript是ECMAScript的扩展语言

      • ECMAScript只提供了最基本的语法,也就是说约定了代码该如何编写

      • 只停留在语言层面,并不能直接用来在实际应用中的功能开发

      • JavaScript实现了ECMAScript的语言标准,并且在此基础之上做了一些扩展,使得我们可以在浏览器环境中

    操作DOM BOM,在node环境中做读写文件之类的操作

    1:JavaScript在浏览器环境当中,等于ECMAScript + Web APIs(web提供的API,即BOM DOM)

    2:node环境中使用JavaScript,等于ECMAScript + Node APIs(如fs net etc.)


    • JavaScript语言本身指的就是ECMAScript

    • 从2015年开始ES开始每年保持一个大版本的迭代,ES2015又被常称为ES6

    • 市面上主流环境开始渐渐支持这些新特性

    • ES2015 — 习惯这之后更新的版本的都叫ES6(特指、泛指)
      • 变化较大,新标准多

    • Nodemon
      • 修改完代码后可以自动执行代码
      • 安装到项目中 yarn add nodemon —dev
      • 使用 yarn nodemon XXX.js

    • 块级作用域
      • let 用花括号括起来的范围{}
      • const
        1. const obj = {}
        2. obj.name = 'zce' //被允许,内存指向只能定义一次,但时面属性可以改变

    • 数组的解构

      1. const arr = [100, 200, 300];
      2. const [, , baz] = arr;
      3. console.log(baz) //300
      4. const [foo, ...rest] = arr;
      5. console.log(rest); //[200, 300] ... 提取级数剩余元素,只能在最后使用
      6. const [foo, bar, baz, more] = arr
      7. console.log(more) //undefined
      8. const [foo, bar, baz = 123, more = 'default value'] = arr
      9. console.log(baz, more) //300 default value

    • 对象的解构
      ```javascript const obj = { name: ‘zce’, age: 18 }

    // const { name } = obj // console.log(name) //zce

    // const name = ‘tom’ // const { name: objName } = obj // console.log(objName) //zce

    const { log } = console log(‘foo’)

    1. - <br />模板字符串
    2. - 支持换行
    3. - 支持插值表达式
    4. ```javascript
    5. // 反引号包裹
    6. // const str = `hello es2015, this is a string`
    7. // 允许换行
    8. // const str = `hello es2015,
    9. // this is a \`string\``
    10. // console.log(str)
    11. const name = 'tom'
    12. // 可以通过 ${} 插入表达式,表达式的执行结果将会输出到对应位置
    13. const msg = `hey, ${name} --- ${1 + 2} ---- ${Math.random()}`
    14. console.log(msg)

    • 带标签的模板字符串

      1. const name = 'tom'
      2. const gender = false
      3. function myTagFunc (strings) {
      4. //console.log(strings) //[ 'hey, ', ' is a ', '.' ]
      5. // return '123'
      6. //const sex = gender ? 'man' : 'woman'
      7. return strings[0] + name + strings[1] + sex + strings[2] //hey, tom is a woman.
      8. }
      9. const result = myTagFunc`hey, ${name} is a ${gender}.`

    • 字符串的扩展方法

      • startsWith()
      • endsWith()
      • includes()

    • 参数默认值

      1. // 默认参数一定是在形参列表的最后
      2. function foo1 (enable = true) {
      3. console.log('foo invoked - enable: ')
      4. console.log(enable)
      5. }
      6. foo1(false) //false 默认参数只有在没有传递实参,或者传递undefined的时候才会被使用

    • 剩余参数

      1. function foo (first, ...args) {
      2. console.log(args)
      3. }
      4. foo(1, 2, 3, 4) //[ 2, 3, 4 ]

    • 展开数组

      1. const arr = ['foo', 'bar', 'baz']
      2. // console.log.apply(console, arr)
      3. console.log(...arr) //与上等效 foo bar baz

    • 箭头函数

      • 箭头函数不会改变this指向

    • 对象字面量的增强
      ```javascript const bar = ‘345’

      const obj = {

      1. foo: 123,
      2. // bar: bar
      3. // 属性名与变量名相同,可以省略 : bar
      4. bar,
      5. // method1: function () {
      6. // console.log('method111')
      7. // }
      8. // 方法可以省略 : function
      9. method1 () {
      10. console.log('method111')
      11. // 这种方法就是普通的函数,同样影响 this 指向。
      12. console.log(this)
      13. },
      14. // Math.random(): 123 // 不允许
      15. // 通过 [] 让表达式的结果作为属性名
    1. [bar]: 123
    2. }
    3. // obj[Math.random()] = 123
    4. console.log(obj)
    5. obj.method1()
    1. - <br />Object.assign<br />
    2. ```javascript
    3. // const source1 = {
    4. // a: 123,
    5. // b: 123
    6. // }
    7. // const source2 = {
    8. // b: 789,
    9. // d: 789
    10. // }
    11. // const target = {
    12. // a: 456,
    13. // c: 456
    14. // }
    15. // const result = Object.assign(target, source1, source2)
    16. // console.log(target) { a:123,c:456,b:789,d:789}
    17. // console.log(result === target) true
    18. // 应用场景
    19. function func (obj) {
    20. // obj.name = 'func obj'
    21. // console.log(obj)
    22. const funcObj = Object.assign({}, obj)
    23. funcObj.name = 'func obj'
    24. console.log(funcObj)
    25. }
    26. const obj = { name: 'global obj' }
    27. func(obj)
    28. console.log(obj)

    • Object.is

      1. console.log(
      2. // 0 == false // => true
      3. // 0 === false // => false
      4. // +0 === -0 // => true
      5. // NaN === NaN // => false
      6. // Object.is(+0, -0) // => false
      7. // Object.is(NaN, NaN) // => true
      8. )

    • Proxy


      • 为对象设置访问代理器

      • 监视到对象的读写过程

      • vue3使用proxy实现数据内部的响应

      • defineProperty只能监视属性的读写

      • Proxy能够监视到更多对象操作,比如delete操作、对对象中方法的调用

      • proxy handler方法,如下图

    proxy方法.png


    • proxy能更好的支持数组对象的监视

      1. // const person = {
      2. // name: 'zce',
      3. // age: 20
      4. // }
      5. // const personProxy = new Proxy(person, {
      6. // // 监视属性读取
      7. // get (target, property) {
      8. // return property in target ? target[property] : 'default'
      9. // // console.log(target, property)
      10. // // return 100
      11. // },
      12. // // 监视属性设置
      13. // set (target, property, value) {
      14. // if (property === 'age') {
      15. // if (!Number.isInteger(value)) {
      16. // throw new TypeError(`${value} is not an int`)
      17. // }
      18. // }
      19. // target[property] = value
      20. // // console.log(target, property, value)
      21. // }
      22. // })
      23. // personProxy.age = 100
      24. // personProxy.gender = true
      25. // console.log(personProxy.name)
      26. // console.log(personProxy.xxx)
      27. // Proxy 对比 Object.defineProperty() ===============
      28. // 优势1:Proxy 可以监视读写以外的操作 --------------------------
      29. // const person = {
      30. // name: 'zce',
      31. // age: 20
      32. // }
      33. // const personProxy = new Proxy(person, {
      34. // deleteProperty (target, property) {
      35. // console.log('delete', property)
      36. // delete target[property]
      37. // }
      38. // })
      39. // delete personProxy.age
      40. // console.log(person)
      41. // 优势2:Proxy 可以很方便的监视数组操作 --------------------------
      42. // const list = []
      43. // const listProxy = new Proxy(list, {
      44. // set (target, property, value) {
      45. // console.log('set', property, value)
      46. // target[property] = value
      47. // return true // 表示设置成功
      48. // }
      49. // })
      50. // listProxy.push(100)
      51. // listProxy.push(100)
      52. // 优势3:Proxy 不需要侵入对象 --------------------------
      53. // const person = {}
      54. // Object.defineProperty(person, 'name', {
      55. // get () {
      56. // console.log('name 被访问')
      57. // return person._name
      58. // },
      59. // set (value) {
      60. // console.log('name 被设置')
      61. // person._name = value
      62. // }
      63. // })
      64. // Object.defineProperty(person, 'age', {
      65. // get () {
      66. // console.log('age 被访问')
      67. // return person._age
      68. // },
      69. // set (value) {
      70. // console.log('age 被设置')
      71. // person._age = value
      72. // }
      73. // })
      74. // person.name = 'jack'
      75. // console.log(person.name)
      76. // Proxy 方式更为合理
      77. const person2 = {
      78. name: 'zce',
      79. age: 20
      80. }
      81. const personProxy = new Proxy(person2, {
      82. get (target, property) {
      83. console.log('get', property)
      84. return target[property]
      85. },
      86. set (target, property, value) {
      87. console.log('set', property, value)
      88. target[property] = value
      89. }
      90. })
      91. personProxy.name = 'jack'
      92. console.log(personProxy.name)

    • Reflect
      • 统一的对象操作API,属于一个静态类
      • Reflect成员方法就是Proxy处理对象的默认实现
    1. // const obj = {
    2. // foo: '123',
    3. // bar: '456'
    4. // }
    5. // const proxy = new Proxy(obj, {
    6. // get (target, property) {
    7. // console.log('watch logic~')
    8. // return Reflect.get(target, property)
    9. // }
    10. // })
    11. // console.log(proxy.foo)
    12. const obj = {
    13. name: 'zce',
    14. age: 18
    15. }
    16. // console.log('name' in obj)
    17. // console.log(delete obj['age'])
    18. // console.log(Object.keys(obj))
    19. console.log(Reflect.has(obj, 'name'))
    20. console.log(Reflect.deleteProperty(obj, 'age'))
    21. console.log(Reflect.ownKeys(obj))

    • class static

      1. class Person {
      2. constructor (name) {
      3. this.name = name
      4. }
      5. say () {
      6. console.log(`hi, my name is ${this.name}`)
      7. }
      8. static create (name) {
      9. return new Person(name)
      10. }
      11. }
      12. // const p = new Person('tom')
      13. // p.say()
      14. const tom = Person.create('tom')
      15. tom.say()

    • extend

      1. class Person {
      2. constructor (name) {
      3. this.name = name
      4. }
      5. say () {
      6. console.log(`hi, my name is ${this.name}`)
      7. }
      8. }
      9. class Student extends Person {
      10. constructor (name, number) {
      11. super(name) // 父类构造函数
      12. this.number = number
      13. }
      14. hello () {
      15. super.say() // 调用父类成员
      16. console.log(`my school number is ${this.number}`)
      17. }
      18. }
      19. const s = new Student('jack', '100')
      20. s.hello()

    • Set 数据结构

      • 集合,与数组类似,但内部成员不允许重复
      • 如果重复添加,会忽略 ```javascript const s = new Set()

        s.add(1).add(2).add(3).add(4).add(2)

        // console.log(s)

        // s.forEach(i => console.log(i))

        // for (let i of s) { // console.log(i) // }

        // console.log(s.size)

        // console.log(s.has(100))

        // console.log(s.delete(3)) console.log(s) //Set { 1, 2, 3, 4 }

    1. // s.clear()
    2. // console.log(s)
    3. // 应用场景:数组去重
    4. const arr = [1, 2, 1, 3, 4, 1]
    5. // const result = Array.from(new Set(arr))
    6. const result = [...new Set(arr)]
    7. console.log(result) //[ 1, 2, 3, 4 ]
    8. // 弱引用版本 WeakSet
    9. // 差异就是 Set 中会对所使用到的数据产生引用
    10. // 即便这个数据在外面被消耗,但是由于 Set 引用了这个数据,所以依然不会回收
    11. // 而 WeakSet 的特点就是不会产生引用,
    12. // 一旦数据销毁,就可以被回收,所以不会产生内存泄漏问题。
    1. - <br />map<br />
    2. ```javascript
    3. // const obj = {}
    4. // obj[true] = 'value'
    5. // obj[123] = 'value'
    6. // obj[{ a: 1 }] = 'value'
    7. // console.log(Object.keys(obj))
    8. // console.log(obj['[object Object]'])
    9. const m = new Map()
    10. const tom = { name: 'tom' }
    11. m.set(tom, 90)
    12. console.log(m) //Map { { name: 'tom' } => 90 }
    13. console.log(m.get(tom)) //90
    14. // m.has()
    15. // m.delete()
    16. // m.clear()
    17. m.forEach((value, key) => {
    18. console.log(value, key) //90 { name: 'tom' }
    19. })
    20. // 弱引用版本 WeakMap
    21. // 差异就是 Map 中会对所使用到的数据产生引用
    22. // 即便这个数据在外面被消耗,但是由于 Map 引用了这个数据,所以依然不会回
    23. // 一旦数据销毁,就可以被回收,所以不会产生内存泄漏问题。

    • Symbol
      • 一种全新的原始数据类型
      • 表示一个独一无二的值
      • 从2015年开始,对象可以直接使用Symbol类型的值作为属性名
      • 最主要的作用就是为对象添加独一无二的属性名
    1. // Symbol 数据类型
    2. // 场景1:扩展对象,属性名冲突问题
    3. // // shared.js ====================================
    4. // const cache = {}
    5. // // a.js =========================================
    6. // cache['a_foo'] = Math.random()
    7. // // b.js =========================================
    8. // cache['b_foo'] = '123'
    9. // console.log(cache)
    10. // =========================================================
    11. // const s = Symbol()
    12. // console.log(s)
    13. // console.log(typeof s)
    14. // 两个 Symbol 永远不会相等
    15. // console.log(
    16. // Symbol() === Symbol()
    17. // )
    18. // Symbol 描述文本
    19. // console.log(Symbol('foo'))
    20. // console.log(Symbol('bar'))
    21. // console.log(Symbol('baz'))
    22. // 使用 Symbol 为对象添加用不重复的键
    23. // const obj = {}
    24. // obj[Symbol()] = '123'
    25. // obj[Symbol()] = '456'
    26. // console.log(obj) //{ [Symbol()]: '123', [Symbol()]: '456' }
    27. // 也可以在计算属性名中使用
    28. // const obj = {
    29. // [Symbol()]: 123
    30. // }
    31. // console.log(obj)
    32. // =========================================================
    33. // 案例2:Symbol 模拟实现私有成员
    34. // a.js ======================================
    35. const name = Symbol()
    36. const person = {
    37. [name]: 'zce',
    38. say () {
    39. console.log(this[name])
    40. }
    41. }
    42. // 只对外暴露 person
    43. // b.js =======================================
    44. // 由于无法创建出一样的 Symbol 值,
    45. // 所以无法直接访问到 person 中的「私有」成员
    46. // person[Symbol()]
    47. person.say()

    • Symbol.for(‘xxx’)
      • 维护了一个全局的注册表,为我们的字符串和symbol值提供了一个一一对应的关系

    • Symbol.toStringTag 是内置的一个Symbol常量,为对象实现迭代器时,会经常用到
    1. // Symbol 补充
    2. // console.log(
    3. // // Symbol() === Symbol()
    4. // Symbol('foo') === Symbol('foo')
    5. // )
    6. // Symbol 全局注册表 ----------------------------------------------------
    7. // const s1 = Symbol.for('foo')
    8. // const s2 = Symbol.for('foo')
    9. // console.log(s1 === s2)
    10. // console.log(
    11. // Symbol.for(true) === Symbol.for('true')
    12. // )
    13. // 内置 Symbol 常量 ---------------------------------------------------
    14. // console.log(Symbol.iterator)
    15. // console.log(Symbol.hasInstance)
    16. // const obj = {
    17. // [Symbol.toStringTag]: 'XObject'
    18. // }
    19. // console.log(obj.toString())
    20. // Symbol 属性名获取 ---------------------------------------------------
    21. const obj = {
    22. [Symbol()]: 'symbol value',
    23. foo: 'normal va1lue'
    24. }
    25. for (var key in obj) {
    26. console.log(key) //foo
    27. }
    28. console.log(obj); //{ foo: 'normal value', [Symbol()]: 'symbol value' }
    29. console.log(Object.keys(obj)) //[ 'foo' ]
    30. console.log(JSON.stringify(obj)) //{"foo":"normal value"}
    31. console.log(Object.getOwnPropertySymbols(obj)) //[ Symbol() ]

    • for-of

      1. // for...of 循环
      2. const arr = [100, 200, 300, 400]
      3. for (const item of arr) {
      4. console.log(item)
      5. }
      6. // for...of 循环可以替代 数组对象的 forEach 方法
      7. arr.forEach(item => {
      8. console.log(item)
      9. })
      10. // for (const item of arr) {
      11. // console.log(item)
      12. // if (item > 100) {
      13. // break
      14. // }
      15. // }
      16. // forEach 无法跳出循环,必须使用 some 或者 every 方法
      17. // arr.forEach() // 不能跳出循环
      18. // arr.some()
      19. // arr.every()
      20. // 遍历 Set 与遍历数组相同
      21. const s = new Set(['foo', 'bar'])
      22. for (const item of s) {
      23. console.log(item)
      24. }
      25. // 遍历 Map 可以配合数组结构语法,直接获取键值
      26. const m = new Map()
      27. m.set('foo', '123')
      28. m.set('bar', '345')
      29. for (const [key, value] of m) {
      30. console.log(key, value)
      31. }
      32. // 普通对象不能被直接 for...of 遍历
      33. const obj = { foo: 123, bar: 456 }
      34. for (const item of obj) {
      35. console.log(item)
      36. }

    • 迭代器(Iterator)

      1. // 迭代器(Iterator)
      2. const set = new Set(['foo', 'bar', 'baz11'])
      3. const iterator = set[Symbol.iterator]()
      4. // console.log(iterator.next())
      5. // console.log(iterator.next())
      6. // console.log(iterator.next())
      7. // console.log(iterator.next())
      8. // console.log(iterator.next())
      9. while (true) {
      10. const current = iterator.next()
      11. if (current.done) {
      12. break // 迭代已经结束了,没必要继续了
      13. }
      14. console.log(current.value)
      15. }

    • 实现可迭代接口(Iterable)

      1. // const obj = {
      2. // [Symbol.iterator]: function () {
      3. // return {
      4. // next: function () {
      5. // return {
      6. // value: 'zce',
      7. // done: true
      8. // }
      9. // }
      10. // }
      11. // }
      12. // }
      13. const obj = {
      14. store: ['foo', 'bar', 'baz'],
      15. [Symbol.iterator]: function () {
      16. let index = 0
      17. const self = this
      18. return {
      19. next: function () {
      20. const result = {
      21. value: self.store[index],
      22. done: index >= self.store.length
      23. }
      24. index++
      25. return result
      26. }
      27. }
      28. }
      29. }
      30. for (const item of obj) {
      31. console.log('循环体', item)
      32. //循环体 foo
      33. //循环体 bar
      34. //循环体 baz
      35. }

    • 迭代器设计模式

    1. // 迭代器设计模式
    2. // 场景:你我协同开发一个任务清单应用
    3. // 我的代码 ===============================
    4. const todos = {
    5. life: ['吃饭', '睡觉', '打豆豆'],
    6. learn: ['语文', '数学', '外语'],
    7. work: ['喝茶'],
    8. // 提供统一遍历访问接口
    9. each: function (callback) {
    10. const all = [].concat(this.life, this.learn, this.work)
    11. for (const item of all) {
    12. callback(item)
    13. }
    14. },
    15. //提供迭代器(ES2015 统一遍历访问接口)
    16. [Symbol.iterator]: function () {
    17. const all = [...this.life, ...this.learn, ...this.work]
    18. let index = 0
    19. return {
    20. next: function () {
    21. return {
    22. value: all[index],
    23. done: index++ >= all.length
    24. }
    25. }
    26. }
    27. }
    28. }
    29. todos.each(function (item) {
    30. console.log(item)
    31. })
    32. console.log('-------------------------------')
    33. for (const item of todos) {
    34. console.log(item)
    35. }
    1. // Generator 应用
    2. // 案例1:发号器
    3. function * createIdMaker () {
    4. let id = 1
    5. while (true) {
    6. yield id++
    7. }
    8. }
    9. const idMaker = createIdMaker()
    10. console.log(idMaker.next().value)
    11. console.log(idMaker.next().value)
    12. console.log(idMaker.next().value)
    13. console.log(idMaker.next().value)
    14. // 案例2:使用 Generator 函数实现 iterator 方法
    15. const todos = {
    16. life: ['吃饭', '睡觉', '打豆豆'],
    17. learn: ['语文', '数学', '外语'],
    18. work: ['喝茶'],
    19. [Symbol.iterator]: function * () {
    20. const all = [...this.life, ...this.learn, ...this.work]
    21. for (const item of all) {
    22. yield item
    23. }
    24. }
    25. }
    26. for (const item of todos) {
    27. console.log(item)
    28. }

    • ES Modules
      • 语言层面的模块化标准
      • 会在模块那里详解

    • ES2016

      • Array.prototype.includes

        1. //旧
        2. const arr = ['foo', 1, NaN, false];
        3. console.log(arr.indexOf('bar')) //-1
        4. console.log(arr.includes('foo')) true
      • 指数运算符

        1. //2的10次方
        2. console.log(Math.pow(2,10));
        3. console.log(2 ** 10);

    • ES2017
      ```javascript const obj = {

      1. foo: 'value1',
      2. bar: 'value2'

      }

      //Object.values() //Object.entries() //Object.getOwnPropertyDescriptors() console.log(Object.values(obj)); //[‘value1’, ‘value2’]

      console.log(Object.entries(obj)); //[[‘foo’, ‘value1’], [‘bar’, ‘value2]]

      for(const [key, value] of Object.entries(obj)) {

      1. console.log(key,value);
      2. //for value1
      3. //bar value2

      }

      console.log(new Map(Object.entries(obj))) //Map { ‘foo’ => ‘value1’, ‘bar’ => ‘value2’ }

    1. const p1 = {
    2. firName: 'Lei',
    3. laName: 'Wang',
    4. get fullName() {
    5. return this.firName + ' ' + this.laName
    6. }
    7. }
    8. const des = Object.getOwnPropertyDescriptors(p1);
    9. const p2 = Object.defineProperties({}, des)
    10. p2.firName = "zce"
    11. console.log(p2.fullName)
    12. //字符串填充方法
    13. //String.prototype.padStart/padEnd
    14. const books = {
    15. html: 5,
    16. css: 16,
    17. javascript: 128
    18. }
    19. for(const [name, count] of Object.entries(books)) {
    20. console.log(`${name.padEnd(16, '-')} | ${count.toString().padStart(3, '0')}`);
    21. }
    22. //在函数参数中添加尾逗号
    23. //如果想重新排列数组顺序,调整起来容易
    24. //如果修改元素中个数,方便插入
    25. const arr = {
    26. 100,
    27. 200,
    28. 300,
    29. }
    30. //Async / Await
    31. //解决异步深嵌

    ```