Contents

总结 ES2015 的所有新特性

总结 ES2015 的所有新特性

💥 ES2015(ES6)是改动最大的一个版本,大体如下:

https://cdn.jsdelivr.net/gh/BallerJay/oss_images@master/blog/2022/06/2022-06-13/image-20220613232421871.png

🍏 let、const关键字和块级作用域

在ES6来临之前,我们习惯于var 关键字声明变量,var声明的变量是属于全局变量,最终会挂载到window对象,这一操作可能会引起一些意外的错误。所以在ES6中加入了constlet 关键字来声明变量。

let v = 100
v = 200
const a = 1
a = 2; // Uncaught TypeError: Assignment to constant variable. 
// 报错,const关键字声明的是一个常量,是不可以改变的(针对于基本数据类型)
{
  var a = 100
}
{
  let b = 100
}
console.log(a) // output: 100
console.log(b) // 报错,b is not defined.  
// let声明的变量只能在当前的`块级作用域({} 之间的区域)`中使用

⚠️ let、const声明的变量存在一个暂时性死区的问题

a = 1;
let a = 0;// Uncaught ReferenceError: Cannot access 'a' before initialization
// 暂时性死区是指使用let、const关键字声明的变量在定义之前是不可以使用的,声明之后才可以使用。

🍐 函数的扩展(函数形参的默认值、箭头函数)

  • 函数默认值

    // es2015之前
    function foo(v) {
      v = v ? v : 100
      return v
    }
    
    // es2015
    function bar(v = 100) {
      return v
    }
    
  • 箭头函数

    function foo(v) {
      return v``
    }
    // 箭头函数写法
    const foo = (v) => {
      return v
    }
    // 简写形式 1
    const foo = v => { // 只有一个参数可以省略括号
      return v
    }
    // 简写形式 2
    const foo = v => v // 语句中只有return时可以省略return和花括号
    

    ⛅️ 补充

    箭头函数与普通函数的区别

    1. 箭头函数中的this指向的是上一级上下文中的this
    2. call、apply、bind方法都无法改变箭头函数的this指向
    3. 箭头函数没有prototype属性
    4. 箭头函数不能作为构造函数使用
    5. 也不能使用new方法
    6. 没有arguments实参列表

    🌊 在ES2015中为函数增加的要给name属性,该属性指向函数的名称。

    function foo(v) {
      return v
    }
    const bar = v => v
    console.log(foo.name) // foo
    console.log(bar.name) // bar
    

🍋 字符串的扩展

​ ES2015中引入了模板字符串的概念,使用反引号**( ` )** 定义,模板字符串会保留格式,且可以使用变量。

// 使用 ` 定义模板字符串
let str = `一碗周`

// 模板字符串可以保留格式
let str2 = `一
周`

// 模板字符串可以使用变量
const myName = '一碗周'
let str3 = `author: ${myName}` // 使用 ${} 进行包裹

​ ES2015还为String和String的示例扩展了一些方法,如下:

方法名 描述
String.fromCodePoint() 用于从 Unicode 码点返回对应字符
String.raw() 返回一个斜杠都被转义(即斜杠前面再加一个斜杠)的字符串,往往用于模板字符串的处理方法。
String.prototype.codePointAt() 返回字符对应码点(String.fromCodePoint()的逆操作)
String.prototype.normalize() 把字符的不同表示方法统一为同样形式,返回新字符串(Unicode正规化)
String.prototype.repeat() 把字符串重复n次,返回处理后的字符串
String.prototype.includes() 判断是否存在指定字符串
String.prototype.startsWith() 判断字符串是否存在原始字符串的头部
String.prototype.endsWith() 判断字符串是否存在原始字符串的尾部

🍉 数组的扩展

ES2015中提供了扩展运算符,即**( … )** ,在数组中使用可以将数组展开,并以逗号分隔。

const arr = [1, 2, 3, 4, 5, 6]
const newArr = [...arr] // 复制数组

console.log(Math.max.call(null, ...arr)) // 将数组中的每一项作为参数使用

除此之外,Array以及数组提供了一系列方法,具体如下:

  • Array.from(): 将类数组对象或者可迭代对象创建一个新的数组,示例代码如下:

    function foo() {
      return Array.from(arguments) // 将 arguments 转换为数组
    }
    
    console.log(foo(1, 2, 3, 4, 5, 6)) // [ 1, 2, 3, 4, 5, 6 ]
    
  • Array.of():创建一个具有可变数量参数的新数组实例,示例代码如下:

    Array.of(1) // [1]
    Array.of(true, 1, '一碗周') // [true, 1, '一碗周']
    
  • Array.prototype.copyWithin(): 浅复制数组的一部分到统一数组中的另一个位置,并返回它,不会改变原数组的长度。示例代码如下:

    const arr = [1, 2, 3, 4]
    
    // 从索引 2 开始,到结束 将内容复制到索引 0 的位置
    arr.copyWithin(0, 2) // [ 3, 4, 3, 4 ]
    
  • Array.prototype.find(): 根据给定的回调函数,找到匹配的第一个元素,找不到返回undefined ,示例代码如下:

    const arr = [1, 2, 3, 4]
    
    arr.find(item => item === 2) // 2(表示元素)、
    
  • Array.prototype.findIndex(): 根据给定的回调函数,找到匹配的第一个元素的索引,找不到返回-1,示例代码如下:

    const arr = [1, 2, 3, 4]
    
    arr.findIndex(item => item === 2) // 1 (表示索引)
    
  • Array.prototype.fill(): 将给定值填充数组,示例代码如下:

    const arr = [1, 2, 3, 4]
    // 将给定值填充索引1-3
    arr.fill('一碗周', 1, 3) // [ 1, '一碗周', '一碗周', 4 ]
    
  • Array.prototype.values(),返回一个可迭代的对象,其内容为数组的value,示例代码如下:

    const arr = [1, true, '一碗周']
    const values = arr.values()
    for (const i of values) {
      console.log(i) // 遍历结果 1 true 一碗周
    }
    
  • Array.prototype.entries():返回一个可迭代的对象,其内容是一个数组,索引0为原数组的元素,1为原数组该位置的值,示例代码如下:

    const arr = [1, true, '一碗周']
    
    const iterator = arr.entries()
    console.log(Array.from(iterator)) // [ [ 0, 1 ], [ 1, true ], [ 2, '一碗周' ] ]
    

🥥 对象的扩展

ES2015中允许对象的属性名和属性值一致时 只写属性名,示例代码如下:

const myName = '一碗周'
const age = 18
const person = { myName, age }
console.log(person) // { myName: '一碗周', age: 18 }

还有允许在定义对象时,允许使用**[ ]**包裹表达式作为属性名,示例代码如下:

const myName = '一碗周'
const age = 18
const person = {
  myName,
  ['a' + 'g' + 'e']: age,
}
console.log(person) // { myName: '一碗周', age: 18 }
  • Object.is():用于比较两个值是否相等,用于解决NaN != NaN, +0 === -0的问题,示例代码如下:

    console.log(NaN === NaN) // false
    console.log(+0 === -0) // true
    
    console.log(Object.is(NaN, NaN)) // true
    console.log(Object.is(+0, -0)) // false
    
  • Object.assign():将所有可枚举属性的值从一个或多个源对象复制到目标对象,并返回目标对象,示例代码如下:

    const person = Object.assign({}, { name: '一碗周' }, { age: 18 })
    console.log(person) // { name: '一碗周', age: 18 }
    
  • Object.getPrototypeOf():获取原型对象。

  • Object.setPrototypeOf():设置原型对象。

🍑 类的概念

在ES2015中提出了类的概念,在语法层面上有了类,示例代码如下:

class Person {
  constructor(age) {
    // 属性
    this.myName = '一碗周'
    this.age = age
  }
  // 静态方法
  // 类(class)通过 static 关键字定义静态方法。不能在类的实例上调用静态方法,而应该通过类本身调用。这些通常是实用程序方法,例如创建或克隆对象的功能。
  static print() {
    console.log()
  }
  // 访问器
  get myName() {
    console.log('getter')
    return '一碗周'
  }
  set myName(v) {
    console.log('setter' + v)
  }
  setName(v) {
    this.myName = v
  }
}
const person = new Person(18)
person.setName('ywanzhou') // 触发 setter 访问器
console.log(person.myName) // 触发 getter 访问器

🍍 模块化

在ES2015中提出了ESModel的模块化规范,这是第一个官方层面的模块化规范,在这个规范中允许我们使用export 导出模块,使用import 引入模块,示例代码如下:

import a from 'm' // 导入模块 m 中的默认导出,将其命名为 a
import a, { b } from 'm' // 导入模块 m 中的默认导出以及单独导入成员 b
import * as A from 'm' // 导入模块中的所有成员
import 'm' // 执行 m 模块

export const b = 1 // 单独导出
export default b // 默认导出
export { b } // 按需导出
export { b as bb } // 改名导出

export { b } from 'm' // 导入模块 m 中的成员 b 并导出

🌶 解构赋值

ES2015新增了解构赋值的语法,允许我们使用按照一定的模式,在数组或者对象中提取指定的值,示例代码如下:

// 数组的解构赋值
let [name, age, hobby = 'coding' /* 结构赋值的默认值 */] = ['一碗周', 18]
// 交换两个变量的值
let a = 1
let b = 2
;[a, b] = [b, a]
console.log(a, b) // 2 1

// 对象的结构赋值
let { name: ObjName /* 解构赋值重命名 */, sex } = { name: '一碗周', sex: 1 }

// 函数参数的解构赋值
function bar({ name, age }) {
  return name + age
}
bar({ name: '一碗周', age: 18 }) // 一碗周18

🫑 Symbol

Symbol 是ES2015中新增的一种数据类型,通过Symbol() 方法创建,可以传递一个字符串作为参数,用于描述该Symbol;通过Symbol() 方法创建的值都是唯一的,示例代码如下:

/**
 * 语法
 * Symbol([description])
 * * description -> 是一个可选的描述信息
 */
// 创建一个 Symbol 类型的值
const mySymbol = Symbol()
console.log(mySymbol) // Symbol()

const myName = Symbol('一碗周')
console.log(typeof myName) // symbol
  • Symbol.for() 方法,示例代码如下:
// Symbol.for('yy') 此API首先会在全局寻找Symbol.for('yy')这个变量,
// 如果有就会把当前这个Symbol赋值到b1中,如果没有就创建一个Symbol再赋值
let b1 = Symbol.for('yy')
let b2 = Symbol.for('yy')
console.log(b1) // Symbol(yy)
console.log(b2) // Symbol(yy)
console.log(b1 === b2) // true

🥕 Promise

Promise是ES2015中提供的一个异步解决方案,解决了回调地狱的问题。

通过Promise() 构造函数可以创建一个promise对象,每一个Promise对象都具有以下几种状态:

  • Pending:初始状态,既不是成功,也不是失败状态。
  • resolved:意味着操作成功完成。
  • rejected:意味着操作失败。

状态的切换只有两种,分别是:

  • pending -> resolved
  • Pending -> rejected

一旦状态发生改变,就不会再次改变。

Promise实例中存在要给then方法,允许我们在Promise实例中链式调用,每个then方法还会返回一个Promise实例,如下图所示:

https://cdn.jsdelivr.net/gh/BallerJay/oss_images@master/blog/2022/06/2022-06-15/image-20220615223704631.png

示例代码如下:

new Promise((resolve, reject) => {
    console.log('我是第一个Promise中的log')
    resolve()
})
    .then(() => {
        console.log('我是第一个then中的log')
    })
    .then(() => {
        console.log('我是第二个then中的log,但是我出现了异常')
        throw new Error('Error')
    })
    .then(() => {
        console.log('我是第三个then中的第一个回调的log,但是我不会执行,因为我上面出现了异常')
    }, () => {
        console.log('我是第三个then中的第二个回调的log,我执行了')
    })
    .then(() => {
        console.log('我是第四个then中的log,我可以正常执行')
    })

/* 执行结果如下
我是第一个Promise中的log
我是第一个then中的log
我是第二个then中的log,但是我出现了异常
我是第三个then中的第二个回调的log,我执行了
我是第四个then中的log,我可以正常执行
*/

有关Promise的一些方法如下:

  • Promise.prototype.then():它最多需要有两个参数:Promise的成功和失败情况的回调函数;
  • Promise.prototype.catch():等于then方法的第二个参数;
  • Promise.all():将多个实例包装成一个新实例,返回全部实例状态变更后的结果数组(齐变更再返回)
  • Promise.race():将多个实例包装成一个新实例,返回全部实例状态优先变更后的结果(先变更先返回)
  • Promise.resolve():将对象转为Promise对象(等价于new Promise(resolve => resolve()))
  • Promise.reject():将对象转为状态为rejected的Promise对象(等价于new Promise((resolve, reject) => reject()))