一篇文章带你学会整个ES6

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

ES 介绍

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

变量

let 变量以及声明特性

  • 语法:

    let a;
    let b, c, d;
    let e = 100;
    let f = 500, g = 'iloveyou', h = []
    复制代码
  • 声明特性:

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

const 变量以及声明特性

  • 语法:

    const SCHOOL = 'xxx大学'
    复制代码
  • 声明特性:

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

ES 6 的变量解构赋值

  • 数组的解构

    const F4 = ['小沈阳', '刘能', '赵四', '宋小宝'];
    
    let [xiao, liu, zhao, song] = F4;
    console.log(xiao)
    console.log(liu)
    console.log(zhao)
    console.log(song)
    复制代码
  • 对象的解构

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

模板字符串

  • 语法:

    let str = `我也是一个字符串`
    复制代码
  • 声明特性:

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

简化对象写法

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

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

函数

箭头函数以及声明特点

  • 语法:

    let fn = function () {
      // 函数体
    }
    
    let fn = () => {
      // 函数体
    }
    复制代码
  • 特性:

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

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

    • 不能使用 arguments 变量。

    • 箭头函数简写:

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

函数参数的默认值

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

    • 形参初始值

      // 形参初始值,具有默认值的参数,一般位置要靠后(潜规则)
      function add(a, b, c=10) {
        return a + b +c
      }
      
      add(1, 2, 3)	// 6
      add(1, 2)	// 13
      复制代码
    • 与解构赋值结合

      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 。

    // ES 5 获取实参的方式:
    function date () {
      console.log(arguments);
    }
    
    date('阿娇', '柏芝', '思慧')
    
    // ES 6 获取实参
    function date(...args) {
      console.log(args);
    }
    
    date('阿娇', '柏芝', '思慧')
    复制代码
  • 注意事项:

    // 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)
    复制代码

扩展运算符

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

    const tfboys = ['易烊千玺', '王源', '王俊凯']
    
    function chunwan () {
      console.log(arguments)
    }
    
    chunwan(...tfboys) //  等价于 chunwan('易烊千玺', '王源', '王俊凯')
    复制代码
  • 应用:

    // 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 的方式

    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

    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 属性的对象。

      注意:需要自定义遍历数据的时候,要想到迭代器。

自定义遍历数据

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);
}
复制代码

生成器函数声明与调用

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

    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)
    }
    复制代码

生成器函数的参数传递

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'))
复制代码

生成器函数实例

  • 回调地狱

    setTimeout(() => {
      console.log(111)
      setTimeout(() => {
      	console.log(222)
        setTimeout(() => {
      		console.log(333)
    		}, 3000)
    	}, 2000)
    }, 1000)
    复制代码
  • 利用生成器函数解决回调地狱:

    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()
    复制代码
  • 生成器函数案例

    // 获取用户数据, 订单数据, 商品数据
        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 方法。
    // 实例化 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 封装读取文件

// 读取文件
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:

    // 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:

    // 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 实践 - 读取多个文件

  • 原生:

    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 版:

    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 失败的回调函数,相当于一个语法糖。

    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 值
  • 应用场景

    // 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 定义静态方法和属性
    • 父类可以重写
    // 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 静态成员

// 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 利用构造函数实现继承

// 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 的类继承

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')
复制代码

子类对父类方法的重写

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 设置

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
分类:
前端
标签: