JavaScript高级语法笔记(三):ES6+常用特性

173 阅读10分钟

ES6+ 常用特性

let 和 const

  • 作用域

    • 全局作用域
    • 函数作用域function() {}
    • 块级作用域{}
  • 作用范围

    • let、const声明的变量,在for,if语句中,会形成块级作用域,块级作用域内的变量,不能被作用域外部使用。
  • 使用

    • 暂时性死区:在代码块内使用const命令和let命令声明变量之前,该变量都不可用。
    • const命令声明常量后必须立即赋值;如果const声明的是基本类型常量,初始化之后不能修改;引用类型的常量,可以修改其成员变量。
    • let命令声明变量后可立即赋值或使用时赋值。
  • 和var的区别

    声明方式变量提升作用域初始值重复定义
    var函数级不需要允许
    let块级不需要不允许
    const块级必需不允许

解构赋值

  • 数组解构

    • 单独解构:根据数组索引,将数组解构成单独的元素

      const arr = [1, 2, 3];
      ​
      const [a, b, c] = arr;
      console.log(a, b, c);//1,2,3
      const [, , d] = arr;
      console.log(d)//3
      
    • 默认值:若数组没有这个元素,解构时可以给变量设置默认值

      const arr = [1, 2, 3];
      ​
      const [, , , defaultVal = '4'] = arr;
      console.log(defaultVal); // 4
      
    • 剩余解构:用 "...+变量名" 解构剩余参数到新数组,只能用一次

      const arr = [1, 2, 3];
      ​
      const [e, ...rest] = arr;
      console.log(rest)//[2, 3]
      
  • 对象解构

    • 单个/多个解构:

       const obj = {name: 'xiaohui', age: 18, height: undefined};
       const {name, age} = obj;
       console.log(name, age) // 'xiaohui', 18
      
    • 解构+重命名:给解构出来的变量重命名

      const obj = {name: 'xiaohui', age: 18, height: undefined};
      const {name: objName} = obj;
      console.log(objName) // 'xiaohui'
      
    • 默认值:给解构变量设置默认值

      const obj = {name: 'xiaohui', age: 18, height: undefined};
      const {height = 1.88} = obj;
      console.log(height) // 1.88
      
  • 应用场景

    • 交换变量值:[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")
  • 注意事项

    • 匹配模式:只要等号两边的模式相同,左边的变量就会被赋予对应的值
    • 解构赋值规则:只要等号右边的值不是对象或数组,就先将其转为对象
    • 解构默认值生效条件:属性值严格等于undefined
    • 解构遵循匹配模式
    • 解构不成功时变量的值等于`undefined``
    • undefinednull无法转为对象,因此无法进行解构、

模板字符串和字符串扩展方法

  • 模板字符串

    • 使用``将字符串包裹起来,可以换行、插值、使用标签函数进行字符串操作

      // 换行
      const str = `fdsjak
      fdsa`
      console.log(str)
      ​
      // 插值
      const strs = `random: ${Math.random()}`;
      console.log(strs)
      ​
      // 标签函数
      ​
      tagFunc = function() {}
      tagFunc`string`
      
  • 字符串扩展方法

    • 字符串遍历:可通过for-of遍历字符串
    • String.raw() :返回把字符串所有变量替换且对斜杠进行转义的结果
    • String.fromCodePoint() :返回码点对应字符
    • codePointAt() :返回字符对应码点(String.fromCodePoint()的逆操作)
    • normalize() :把字符的不同表示方法统一为同样形式,返回新字符串(Unicode正规化)
    • repeat() :把字符串重复n次,返回新字符串
    • matchAll() :返回正则表达式在字符串的所有匹配
    • includes() :是否存在指定字符串
    • startsWith() :是否存在字符串头部指定字符串
    • endsWith() :是否存在字符串尾部指定字符串

    函数扩展

  • 给函数形参设置默认值

    // 带默认参数的形参一般放在后面,减少传参导致的错误几率
    const defaultParams = function (name,age = 0) {
      return [age, name]
    };
    console.log(defaultParams(1))
    
  • 使用...rest形式设置剩余形参,支持无限参数

    // 剩余参数,转化成数组
    const restParams = function(...args) {
        console.log(args.toString());//1, 2, 3, 4, 5
    }
    ​
    restParams(1, 2, 3, 4, 5)
    
  • 箭头函数

    • 使用

      • 无参数:() => {}

      • 单个参数:x => {}

      • 多个参数:(x, y) => {}

      • 解构参数:({x, y}) => {}

      • 嵌套使用:部署管道机制

      • this指向固定化

        • 并非因为内部有绑定this的机制,而是根本没有自己的this,导致内部的this就是外层代码块的this
        • 因为没有this,因此不能用作构造函数
    • 注意事项

      • 函数体内的this定义时所在的对象而不是使用时所在的对象
      • 可让this指向固定化,这种特性很有利于封装回调函数
      • 不可当作构造函数,因此箭头函数不可使用new命令
      • 不可使用yield命令,因此箭头函数不能用作Generator函数
      • 不可使用Arguments对象,此对象在函数体内不存在(可用rest/spread参数代替)
      • 返回对象时必须在对象外面加上括号

数组扩展

  • 扩展方法

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

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

      • 类数组对象:包含length的对象Arguments对象NodeList对象
      • 可遍历对象:StringSet结构Map结构Generator函数
    • Array.of() :转换一组值为真正数组,返回新数组

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

    • find() :返回第一个符合条件的成员
    • findIndex() :返回第一个符合条件的成员索引值
    • fill() :根据指定值填充整个数组,返回原数组
    • keys() :返回以索引值为遍历器的对象
    • values() :返回以属性值为遍历器的对象
    • entries() :返回以索引值和属性值为遍历器的对象
    • 数组空位:ES6明确将数组空位转为undefined(空位处理规不一,建议避免出现)
  • 应用

    • 克隆数组: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

Symbol

  • JavaScript第六种原始数据类型,用来定义一个唯一的变量

  • 方法

    • Symbol() :创建以参数作为描述的Symbol值(不登记在全局环境)
    • Symbol.for() :创建以参数作为描述的Symbol值,如存在此参数则返回原有的Symbol值(先搜索后创建,登记在全局环境)
    • Symbol.keyFor() :返回已登记的Symbol值的描述(只能返回Symbol.for()key)
    • Object.getOwnPropertySymbols() :返回对象中所有用作属性名的Symbol值的数组
  • 应用场景

    • 唯一化对象属性名:属性名属于Symbol类型,就都是独一无二的,可保证不会与其他属性名产生冲突
    • 消除魔术字符串:在代码中多次出现且与代码形成强耦合的某一个具体的字符串或数值
    • 遍历属性名:无法通过for-infor-ofObject.keys()Object.getOwnPropertyNames()JSON.stringify()返回,只能通过Object.getOwnPropertySymbols返回
    • 启用模块的Singleton模式:调用一个类在任何时候返回同一个实例(windowglobal),使用Symbol.for()来模拟全局的Singleton模式
  • 注意事项

    • Symbol()生成一个原始类型的值不是对象,因此Symbol()前不能使用`new命令
    • Symbol()参数表示对当前Symbol值的描述,相同参数的Symbol()返回值不相等
    • Symbol值不能与其他类型的值进行运算
    • Symbol值可通过String()toString()显式转为字符串
    • Symbol值作为对象属性名时,此属性是公开属性,但不是私有属性
    • Symbol值作为对象属性名时,只能用方括号运算符([])读取,不能用点运算符(.)读取
    • Symbol值作为对象属性名时,不会被常规方法遍历得到,可利用此特性为对象定义`非私有但又只用于内部的方法。

    Set和WeakSet

  • Set

    • 定义:类似于数组的数据结构,成员值都是唯一且没有重复的值

    • 属性

      • 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))
  • WeakSet

    • 定义:和Set结构类似,成员值只能是对象

    • 应用场景

      • 储存DOM节点:DOM节点被移除时自动释放此成员,不用担心这些节点从文档移除时会引发内存泄漏
      • 临时存放一组对象或存放跟对象绑定的信息:只要这些对象在外部消失,它在WeakSet结构中的引用就会自动消
    • 注意事项

      • 成员都是弱引用,垃圾回收机制不考虑WeakSet结构对此成员的引用
      • 成员不适合引用,它会随时消失,因此ES6规定WeakSet结构不可遍历
      • 其他对象不再引用成员时,垃圾回收机制会自动回收此成员所占用的内存,不考虑此成员是否还存在于WeakSet结构

Map和WeakMap

  • Map

    • 定义:类似于对象的数据结构,成员键是任何类型的值

    • 属性

      • constructor:构造函数,返回Map
      • size:返回实例成员总数
    • 方法

      • get() :返回键值对
      • set() :添加键值对,返回实例
      • delete() :删除键值对,返回布尔
      • has() :检查键值对,返回布尔
      • clear() :清除所有成员
      • keys() :返回以键为遍历器的对象
      • values() :返回以值为遍历器的对象
      • entries() :返回以键和值为遍历器的对象
      • forEach() :使用回调函数遍历每个成员
    • 注意事项

      • 遍历顺序:插入顺序
      • 对同一个键多次赋值,后面的值将覆盖前面的值
      • 对同一个对象的引用,被视为一个键
      • 对同样值的两个实例,被视为两个键
      • 键跟内存地址绑定,只要内存地址不一样就视为两个键
      • 添加多个以NaN作为键时,只会存在一个以NaN作为键的值
      • Object结构提供字符串—值的对应,Map结构提供值—值的对应
  • WeakMap

    • 定义:和Map结构类似,成员键只能是对象

    • 应用场景

      • 储存DOM节点:DOM节点被移除时自动释放此成员键,不用担心这些节点从文档移除时会引发内存泄漏
      • 部署私有属性:内部属性是实例的弱引用,删除实例时它们也随之消失,不会造成内存泄漏
    • 注意事项

      • 成员键都是弱引用,垃圾回收机制不考虑WeakMap结构对此成员键的引用
      • 成员键不适合引用,它会随时消失,因此ES6规定WeakMap结构不可遍历
      • 其他对象不再引用成员键时,垃圾回收机制会自动回收此成员所占用的内存,不考虑此成员是否还存在于WeakMap结构
      • 一旦不再需要,成员会自动消失,不用手动删除引用
      • 弱引用的只是键而不是值,值依然是正常引用
      • 即使在外部消除了成员键的引用,内部的成员值依然存在

      ES2016

ES2016

ES2017

ES2017

ES2018

ES2018

ES2019

ES2019

ES2020

ES2020