一文带你学会整个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
#前端##前端工程师#
* 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
#前端##前端工程师#