一文带你学会整个ES6

ES 介绍
* ES 全称 EcmaScript,是脚本语言的 `规范` ,而平时经常编写的 `JavaScript` ,是 EcmsScript 的 `一种实现` ,所以 ES 新特性其实是指 `JavaScript 的新特性` 。
* 特点:
  * 语法简单,功能丰富。
  * 框架开发应用。

## 变量
---

### let 变量以及声明特性

* 语法:

  ```JavaScript
  let a;
  let b, c, d;
  let e = 100;
  let f = 500, g = 'iloveyou', h = []
  ```

* 声明特性:

  * 变量不能重复声明。
  * 块级作用域(只在代码块中才能使用)。
  * 不存在变量提升。
  * 不影响作用域链。

### const 变量以及声明特性

* 语法:

  ```JavaScript
  const SCHOOL = 'xxx大学'
  ```

* 声明特性:

  * 一定要赋初始值。
  * 一般变量使用大写(潜规则)。
  * 常量的值不能修改。
  * 块级作用域。
  * 对于数组和对象的元素修改,不算做对常量的修改,不会报错。(原因:数组指向的地址值没有发生改变。)

### ES 6 的变量解构赋值

* 数组的解构

  ```JavaScript
  const F4 = ['小沈阳', '刘能', '赵四', '宋小宝'];
  
  let [xiao, liu, zhao, song] = F4;
  console.log(xiao)
  console.log(liu)
  console.log(zhao)
  console.log(song)
  ```

* 对象的解构

  ```javascript
  const zhao = {
    name: '赵本山',
    age: '不详',
    xiaopin: function () {
      console.log("我可以演小品")
    }
  }
  
  let { name, age, xiaopin } = zhao
  console.log(name)
  console.log(age)
  console.log(xiaopin)
  xiaopin()
  ```

### 模板字符串

* 语法:

  ```JavaScript
  let str = `我也是一个字符串`
  ```

* 声明特性:

  * 内容中可以直接出现换行符。
  * 变量拼接。

### 简化对象写法

---

* ES 6 允许在大括号里面 ,直接写入变量和函数,作为对象的属性和方法。

  ```JavaScript
  let name = 'xxx'
  let change = function () {
    console,log('我可以改变你')
  }
  
  const school = {
    name,    // 等价于 name: name
    change    // 等价于 change: change
    improve () {
      console.log('我们可以提高你的技能')
    }
  }
  ```

## 函数

---

### 箭头函数以及声明特点

* 语法:

  ```JavaScript
  let fn = function () {
    // 函数体
  }
  
  let fn = () => {
    // 函数体
  }
  ```

* 特性:

  * this 是静态的,this 始终指向函数声明时所在作用域下的 this 的值。

  * 不能作为构造函数实例化对象。

  * 不能使用 arguments 变量。

  * 箭头函数简写:

    ```javascript
    // 当形参有且仅有一个的时候,可以省略括号
    let add = n => {
      return n + n;
    }
    // 当函数体只有一条语句时,此时花括号可以省略,return 必须省略。而且语句的执行结果就是函数的返回值。
    let pow = n => n * n;
    ```

### 函数参数的默认值

* ES 6 允许给函数参数赋值初始值。

  * 形参初始值

    ```javascript
    // 形参初始值,具有默认值的参数,一般位置要靠后(潜规则)
    function add(a, b, c=10) {
      return a + b +c
    }
    
    add(1, 2, 3)    // 6
    add(1, 2)    // 13
    ```

  * 与解构赋值结合

    ```javascript
    function connect ({ host="127.0.0.1", username, password, port }) {
      console.log(host)
      console.log(username)
      console.log(password)
      console.log(port)
    }
    
    connect({
      host: 'localhost',
      username: 'root',
      password: 'root',
      port: 3306
    })
    ```

### ES 6 的 rest 函数

* ES 6 引入 rest 函数,用于获取函数的实参,用来代替 arguments 。

  ```javascript
  // ES 5 获取实参的方式:
  function date () {
    console.log(arguments);
  }
  
  date('阿娇', '柏芝', '思慧')
  
  // ES 6 获取实参
  function date(...args) {
    console.log(args);
  }
  
  date('阿娇', '柏芝', '思慧')
  ```

* 注意事项:

  ```javascript
  // rest 参数必须放到参数最后
  function fn(a, b, ...args) {
    console.log(a);    // 1
    console.log(b);    // 2
    console.log(args);    // [3, 4, 5, 6]
  }
  
  fn(1, 2, 3, 4, 5, 6)
  ```

### 扩展运算符

* `...` :扩展运算符能将 `数组` 转换为逗号分隔的 `参数序列` 。

  ```javascript
  const tfboys = ['易烊千玺', '王源', '王俊凯']
  
  function chunwan () {
    console.log(arguments)
  }
  
  chunwan(...tfboys) //  等价于 chunwan('易烊千玺', '王源', '王俊凯')
  ```

* 应用:

  ```javascript
  // 1. 数组的合并
  const tfboys = ['易烊千玺', '王源', '王俊凯']
  const kuiazi = ['王太利', '肖央']
  
  const newGroup = [...kuaizi, ...tfboys]
  
  // 2. 数组的克隆
  const sanzhihua = ['E', 'G', 'M']
  const sanyecao = [...sanzhihua] // 浅拷贝
  
  // 3. 将伪数组转为真正的数组
  const divs = document.querySelectorAll('div')
  const divArr = [...divs]    // 此时就变成了真正的数组
  ```

## 数据类型

---

### Symbol

* ES 6 引入了一种新的原始数据类型 Symbol ,表示独一无二的值,它是 JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型。

* 特点:

  * Symbol 的值是唯一的,用来解决命名冲突的问题。
  * Sysbol 值不能与其他数据进行运算。
  * Symbol 定义的对象属性不能使用 for...in 循环遍历,但是可以使用 `Reflect.ownKeys` 来获取对象的所有键名。

* 创建 Symbol 的方式

  ```JavaScript
  let s = Symbol()
  let s2 = Symbol('标识符1')
  let s3 = Symbol('标识符1')
  console.log(s2 === s3)    // false
  // Symbol.for 创建
  let s4 = Symbol.for('标识符2')
  let s5 = Symbol.for('标识符2')
  console.log(s4 === s5)    // true
  ```

#### 对象添加 Symbol 类型的属性

* 向对象中添加方法 up down

  ```javascript
  let game = {
    name: '俄罗斯方块',
    up: function () {},
    down: function () {}
  }
  
  // 1. 声明一个对象
  let methods = {
    up: Symbol(),
    down: Symbol()
  }
  // 2. 将声明的对象中的 up 和 down 添加到 game 中
  game[methods.up] = function () {
    console.log('我可以改变形状')
  }
  game[methods.down] = function () {
    console.log('我可以改变大小')
  }
  
  
  let youxi = {
    name: '狼人杀',
    [Symbol('say')]: funcyion () {
        console.log('我可以发言')
      },
    [Symbol('zibao')]: funcyion () {
        console.log('我可以自爆')
      }
  }
  ```

#### Symbol 内置值

* 除了定义自己使用的 Symbol 值以外, ES 6 还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法。

## 迭代器

---

* 迭代器(iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 itrator 接口,就可以完成遍历操作。
  
  * ES 6 创造了一种新的遍历命令 for...on 循环,Iterator 接口主要提供 for...on 消费。
  
  * 原生具有 Itrator 接口的数据(可用 for...of 遍历)。
  
    * Array
    * Arguments
    * Set
    * Map
    * String
    * TypedArray
    * NodeList
  
  * 工作原理:
  
    * 创建一个指针对象,指向一个当前数据结构的起始位置。
    * 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员。
    * 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员。
    * 每调用 next 方法返回一个包含 value 和 down 属性的对象。
  
    **`注意:需要自定义遍历数据的时候,要想到迭代器。`**

### 自定义遍历数据

```javascript
const banji = {
  name: '终极一班',
  stus: [
    '汪大东',
    '雷婷',
    '中万钧',
    '金宝三'
  ],
  [Symbol.iterator] () {
    let index = 0
    let _this = this
    return {
      next: function() {
        if (index < _this.stus.length) {
          const result = { value: _this.stus[index], down: false }
          index++
          return result
        } else {
          return { value: undefined, down: true }
        }
      }
    }
  }
}

for (let v of banji) {
  console.log(v);
}
```

## 生成器函数声明与调用

---

* 生成器就是一个特殊的函数,来进行异步编程。

  ```JavaScript
  function * gen(){
    console.log('111')
    yield '一只没有耳朵'    // yield: 函数代码的分隔符
    console.log('222')
    yield '一只没有耳朵'
    console.log('333')
    yield '一只没有耳朵'
    console.log('444')
  }
  
  let iterator = gen()
  console.log(iterator.next())
  console.log(iterator.next())
  console.log(iterator.next())
  console.log(iterator.next())
  
  // 遍历
  for(let v of gen()){
    console.log(v)
  }
  ```

### 生成器函数的参数传递

```javascript
function * gen(arg){
  console.log(arg)    // AAA
  let one = yield 111    // yield: 函数代码的分隔符
  console.log(one)    // BBB
  let two = yield 222
  console.log(two)    // CCC
  let three = yield 333
  console.log(three)    // DDD
}

let iterator = gen('AAA')
console.log(iterator.next('BBB'))
console.log(iterator.next('CCC'))
console.log(iterator.next('DDD'))
```

### 生成器函数实例

* 回调地狱

  ```javascript
  setTimeout(() => {
    console.log(111)
    setTimeout(() => {
        console.log(222)
      setTimeout(() => {
            console.log(333)
          }, 3000)
      }, 2000)
  }, 1000)
  ```

* 利用生成器函数解决回调地狱:

  ```javascript
  function one() {
    setTimeout(() => {
      console.log(111)
      iterator.next()
    },1000)
  }
  
  function two() {
    setTimeout(() => {
      console.log(222)
      iterator.next()
    },2000)
  }
  
  function three() {
    setTimeout(() => {
      console.log(333)
      iterator.next()
    },3000)
  }
  
  function * gen() {
    yield one()
    yield two()
    yield three()
  }
  // 调用生成器函数
  let iterator = gen()
  iterator.next()
  ```

* 生成器函数案例

  ```javascript
  // 获取用户数据, 订单数据, 商品数据
      function getUser() {
        setTimeout(() => {
          let data = '用户数据'
          iterator.next(data)
        }, 1000)
      }
  
      function getOrder() {
        setTimeout(() => {
          let data = '订单数据'
          iterator.next(data)
        }, 1000)
      }
  
      function getGoods() {
        setTimeout(() => {
          let data = '商品数据'
          iterator.next(data)
        }, 1000)
      }
  
      function* gen() {
        let user = yield getUser()
        console.log(user);
        let order = yield getOrder()
        console.log(order);
        let goods = yield getGoods()
        console.log(goods);
      }
      // 调用生成器函数
      let iterator = gen()
      iterator.next()
  ```

## Promise

---

* Promise 是 ES 6 引入的异步编程的新解决方案。语法上 Promise 是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。

  * Promise 构造函数:`Promise(excutor){}` 。
  * Promise.prototype.then 方法。
  * Promise.prototype.catch 方法。

  ```JavaScript
  // 实例化 Promise 对象
      const p = new Promise(function(resolve, reject){
        setTimeout(function(){
          // 成功时调用 resolve
          let data = '数据库中的数据'
          resolve(data)
          // 失败时调用 reject
          let err = '数据读取失败'
          reject(err)
        }, 1000)
      })
  
      // 调用 Promise 对象的 then 方法
      p.then(function(value){
        console.log(value);
      }, function(reason){
        console.log(reason);
      })
  ```

### Promise 封装读取文件

```javascript
// 读取文件
fs.readFile(文件路径, (err, data) => {
  // 如果失败,则抛出错误
  if(err) throw err
  // 如果没有出错,则输出内容
  console.log(data.toString())
})

// 用 promise 封装读取文件
const p = new Promise(function(resolve, reject){
  fs.readFile(文件路径, (err, data)=> {
    // 判断如果失败
    if(err) reject(err)
    // 如果成功
    resolve(data)
  })
})

p.then(function(value){
  console.log(value.toString)
}, function(reason){
  console.log("读取失败!!")
})
```

### Promise 封装 AJAX

* 原生 AJAX:

  ```JavaScript
  // 1. 创建对象
  const xhr = new XMLHttpRequest()
  // 2. 初始化
  xhr.open("GET", 接口地址)
  // 3. 发送   
  xhr.send()
  // 4. 绑定事件,处理响应结果
  xhr.onreadystatechange = function () {
    // 判断
    if (xhr.readyState === 4) {
      // 判断响应状态码 200-299
      if (xhr.status >= 200 && xhr.status < 300) {
        // 表示成功
        console.log(xhr.response);
      } else {
        console.error(xhr.status);
      }
    }
  }
  ```
  
* Promise 封装 AJAX:

  ```JavaScript
  // Promise 封装 AJAX
  const p = new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest()
    xhr.open("GET", 接口地址)
    xhr.send()
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        if (xhr.status >= 200 && xhr.status < 300) {
          resolve(xhr.response);
        } else {
          reject(xhr.status);
        }
      }
    }
  })
  
  p.then(function(value){
    console.log(value);
  }, function (reason) {
    console.log(reason);
  })
  ```


### Promise.prototype.then 方法

* 调用 then 方法,then 方法的返回结果是 Promise 对象,对象状态由回调函数的执行结果决定。
  * 如果回调函数中返回的结果是 非 Promise 类型的属性,状态为成功,返回值为对象的成功的值。

### Promise 实践 - 读取多个文件

* 原生:

  ```JavaScript
  const fs = require('fs')
  
  fs.readFile(文件路径, (err, data1) => {
    fs.readFile(文件路径, (err, data2) => {
      fs.readFile(文件路径, (err, data3) => {
        let result = data1 + '\r\n' + data2 + '\r\n' + data3
        console.log(result);
      })
    })
  })
  ```

* Promise 版:

  ```JavaScript
  const p = new Promise((resolve, reject) => {
    fs.readFile(文件路径, (err, data) => {
      resolve(data)
    })
  })
  
  p.then(value => {
    return new Promise((resolve, reject) => {
      fs.readFile(文件路径, (err, data) => {
        resolve([value, data])
      })
    })
  }).then(value => {
    return new Promise((resolve, reject) => {
      fs.readFile(文件路径, (err, data) => {
        value.push(data)
        resolve(value)
      })
    })
  }).then(value => {
    console.log(value);
  })
  ```

### Promise 的 catch 方法

* 用来捕获 Promise 失败的回调函数,相当于一个语法糖。

  ```JavaScript
  const p = new Promise((resolve, reject) => {
    setTimeout(() => {
      reject('出错了')
    })
  })
  
  // p.then(function(value){}, function(reason){
  //   console.error(reason);
  // })
  
  p.catch(function(reason){
    console.warn(reason);
  })
  ```

## 数据结构

---

### Set

* ES 6 提供了新的数据结构 Set (集合)。它类似于数组,但成员的值都是唯一的,集合实现了 iterator 接口,所以可以使用 【扩展运算符】和 【for...of...】进行遍历,集合的属性和方法:

  | 属性或方法 | 说明                                        |
  | ---------- | ------------------------------------------- |
  | size       | 返回集合的元素个数                          |
  | add        | 增加一个新元素,返回当前集合                |
  | delete     | 删除元素,返回 boolean 值                   |
  | has        | 检测集合中是否包含某个元素,返回 Boolean 值 |

* 应用场景

  ```JavaScript
  // 1. 数组去重
  let arr = [1,2,2,4,3,5,5,3,2,6]
  let reasult = [...new Set(arr)]
  // 2. 交集
  let arr2 = [4,4,5,4,6,5]
  let reasult = [....new Set(arr)].fifter(item => {
    let s2 = new Set(arr2)
    if (s2.has(item)) {
      return true
    } else {
      return false
    }
  })
  // 上面的代码可以简化为:let result = [...new Set(arr)].fifter(item => new Set(arr2).has(item))
  // 3. 并集
  let union = [...new Set([...arr, ...arr2])]
  // 4. 差集
  let diff = [...new Set(arr)].fifter(item => !(new Set(arr2).has(item)))
  ```

### Map

* ES 6 tigongle  Map 数据结构。它类似于对象,也是键值对的集合。但是“健”的范围不限于字符串,各种类型的值(包括对象)都可以当作荐。Map 也实现了 iterator 接口,所以可以使用【扩展运算符】和 【for...of...】进行遍历。Map 的属性和方法:

  | 属性或方法 | 说明                                         |
  | ---------- | -------------------------------------------- |
  | size       | 返回 Map 的元素个数                          |
  | set        | 增加一个新元素,返回当前 Map                 |
  | get        | 返回键名对象的键值                           |
  | has        | 检测 Map 中是否包含某个元素,返回 Boolean 值 |
  | clear      | 清空集合, 返回 undefined                    |

## class 类

---

* ES 6 提供了更接近传统语言的写法,引入了 Class (类)这个概念,作为对象的模板。通过 class 关键字,可以定义类。基本上,ES 6 的 class 可以看作只是一个语法糖,它的绝大部分功能, ES 5 都可以做到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。

* 知识点:

  * class 声明类
  * constructor 定义构造函数
  * extends 继承父类
  * super 调用父级构造方法
  * static 定义静态方法和属性
  * 父类可以重写

  ```JavaScript
  // ES 5 语法
  function Phone(brand, price) {
    this.brand = brand
    this.price = price
  }
  
  Phone.prototype.call = function () {
    console.log('我可以打电话');
  }
  // 实例化对象
  let Huawei = new Phone('华为', 5999)
  
  // ES 6 语法
  class Shouji {
    constructor(brand, price) {
      this.brand = brand
      this.price = price
    }
    call(){
      console.log('我可以打电话');
    }
  }
  
  let onePlus = new Shouji('1+', 1999)
  ```

### class 静态成员

```javascript
// ES 5
function Phone(){
  
}
Phone.name = '手机'
Phone.change = function(){
  console.log('我可以改变世界')
}
Phone.prototype.size = '5.5inch'
let nokia = new Phone()
console.log(nokia.name)    // undefined
console.log(nokia.size)    // 5.5inch

// ES 6
class Phone{
  // 静态属性
  static name = '手机'
    static change(){
    console.log('我可以改变世界')
  }
}
let nokia = new Phone()
console.log(nokia.name)    // undefined
console.log(Phone.name)    // 手机
```

### ES 5 利用构造函数实现继承

```javascript
// ES 5 语法
function Phone(brand, price) {
  this.brand = brand
  this.price = price
}

Phone.prototype.call = function () {
  console.log('我可以打电话');
}

function SmartPhone(brand, price, color, size) {
  Phone.call(this, brand, price)
  this.color = color
  this.size = size
}
// 设置子级构造函数的原型
SmartPhone.prototype = new Phone
SmartPhone.prototype.constructor = SmartPhone
// 声明子类的方法
SmartPhone.prototype.photo = function () {
  console.log("我可以拍照");
}
SmartPhone.prototype.playGame = function () {
  console.log("我可以玩游戏");
}
const chuizi = new SmartPhone('锤子', 2499, '黑色', '5.5inch')
```

### ES 6 的类继承

```javascript
class Phone {
  constructor(brand, price) {
    this.brand = brand
    this.price = price
  }
  // 父类的成员属性
  call() {
    console.log('我可以打电话');
  }
}

class SmartPhone extends Phone {
  constructor(brand, price, color, size) {
    super(brand, price)
    this.color = color
    this.size = size
  }
  photo() {
    console.log('我可以拍照');
  }
  playGame() {
    console.log('我可以玩游戏');
  }
}
const xiaomi = new SmartPhone('小米', 799, '黑色', '4.7inch')
```

### 子类对父类方法的重写

```JavaScript
class Phone {
  constructor(brand, price) {
    this.brand = brand
    this.price = price
  }
  // 父类的成员属性
  call() {
    console.log('我可以打电话');
  }
}

class SmartPhone extends Phone {
  constructor(brand, price, color, size) {
    super(brand, price)
    this.color = color
    this.size = size
  }
  photo() {
    console.log('我可以拍照');
  }
  playGame() {
    console.log('我可以玩游戏');
  }
  call() {
    console.log('我可以视频通话')
  }
}
const xiaomi = new SmartPhone('小米', 799, '黑色', '4.7inch')
```

### class 中的 getter 和 setter 设置

```js
class Phone {
  get price(){
    console.log("价格属性被读取了")
    return 'iloveyou'
  }

  set price(newVal){
    console.log("价格属性被修改了")
  }
}
// 实例化对象
let s = new Phone()
console.log(s.price); // 调用 get 方法,得到的结果是返回值 
s.price = 'free'  // 调用 set 方法
```

## ES 6 的数值扩展

---

| 数值扩展                         | 说明                             |
| -------------------------------- | -------------------------------- |
| Number.EPSILON                   | 是 JavaScript 表示的最小精度     |
| 二进制、八进制、十进制、十六进制 |                                  |
| Number.isFinite                  | 检测一个数值是否为有限数         |
| Number.isNaN                     | 检测一个数值是否为 NaN           |
| Number.parseInt                  | 字符串转整数                     |
| Number.parseFloat                | 字符串转整数                     |
| Number.isInteger                 | 判断一个数是否为整数             |
| Math.trunc                       | 将数字的小数部分抹掉             |
| Math.sign                        | 判断一个数到底为正数,负数还是零 |

## ES 6 的对象扩展

---

| 对象扩展              | 说明                   |
| --------------------- | ---------------------- |
| Object.is             | 判断两个值是否完全相等 |
| Object.assign         | 对象的合并             |
| Object.setPrototypeOf | 设置原型对象           |
| Object.getPrototypeOf |                        |

## 模块化

---

* 模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来。

### 模块化的好处

* 防止命名冲突。
* 代码复用。
* 高维护性。

### 模块化规范产品

* ES 6 之前的模块化规范:
  * CommonJS => NodeJS\Browserify
  * AMD => requireJS
  * CMD => seaJS

### ES 6 模块化语法

* 模块功能主要由两个命令构成:export 和 import 。
  * export 命令用于规定模块的对外接口。
  * import 命令用于输入其他模块提供的功能。

### 使用 babel 对 ES 6 模块化代码转换

* 步骤:
  * 安装工具 babel-cli babel-preset-env browserify(webpack)
  * npx babel src/js -d dist/js
  * 打包 npx browserify dist/js/app.js -o dist/bundle.js
#前端##前端工程师#
全部评论
好难,不过能学
点赞 回复 分享
发布于 2022-08-26 21:49 河北
学会整个ES6了兄弟
点赞 回复 分享
发布于 2022-08-26 20:46 湖南

相关推荐

06-07 19:59
门头沟学院 C++
补药卡我啊😭:都快15年前的了还在11新特性
你的简历改到第几版了
点赞 评论 收藏
分享
06-26 15:33
青岛工学院 Java
积极的秋田犬要冲国企:他现在邀请我明天面试
点赞 评论 收藏
分享
评论
5
10
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务