# ES6
# 1. ES6 简介
# 1.1 什么是 ES6 ?
ES的全称是ECMAScript,它是由ECMA国际标准化组织,制定的一项脚本语言的标准化规范。
ES6实际上是一个泛指,泛指 ES2015及后续版本
# 1.2 为什么使用 ES6 ?
每一次标准的诞生都意味着语言的完善,功能的加强。JavaScript语言本身也有一些令人不满意的地方。
- 变量提升特性增加了程序运行时的不可预测性
- 语法过于松散,实现相同的功能,不同的人可能会写出不同的代码
# 2. ES6 的新增语法
# 2.1 let
ES6中新增的用于声明变量的关键字
let 关键字用来声明变量,使用 let 声明的变量有几个特点:
- 不允许重复声明
- 块级作用域
- 不存在变量提升
- 不影响作用域链
<script>
//声明变量
let a;
let b,c,d;
let e = 100;
let f = 521, g = 'iloveyou', h = [];
//1. 变量不能重复声明
// let star = '罗志祥';
// let star = '小猪';
//2. 块级作用域 全局, 函数, eval
// if else while for
// {
// let girl = '周扬青';
// }
// console.log(girl);
//3. 不存在变量提升
// console.log(song);
// let song = '恋爱达人';
//4. 不影响作用域链
{
let school = '学校';
function fn(){
console.log(school);
}
fn();
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
应用场景:以后声明变量使用 let 就对了
代码示例
<body>
<div class="container">
<h2 class="page-header">点击切换颜色</h2>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
<script>
//获取div元素对象
let items = document.getElementsByClassName('item');
//遍历并绑定事件
for(let i = 0;i<items.length;i++){
items[i].onclick = function(){
//修改当前元素的背景颜色
// this.style.background = 'pink';
items[i].style.background = 'pink';
}
}
</script>
</body>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
这里如果使用 var 只有一个作用域 因为异步的原因没点击之前 i 就会变成 3
使用 let 将会产生多个作用域
解决方法有
- 立即执行函数
- 事件委托
- 将索引保存到 item[i]
- 使用 let
# 2.2 const
const 关键字用来声明常量,const 声明有以下特点:
- 声明必须赋初始值
- 标识符一般为大写
- 不允许重复声明
- 值不允许修改
- 块级作用域
注意: 对象属性修改和数组元素变化不会触发
const错误应用场景:声明对象类型使用
const,非对象类型声明选择let
代码示例
<script>
// 声明常量
const SCHOOL = '菠萝'
// 1. 一定要赋初始值
// const A;
// 2. 一般常量使用大写(潜规则)
// const a = 100;
// 3. 常量值不能修改
// SCHOOL = 'Boluo'
// 4. 块级作用域
// {
// const PLAYER = 'uzi'
// }
// console.log(PLAYER);
// 5. 对于数组和对象的元素修改,不算做对常量的修改,不会报错
const TEAM = ['UZI', 'MLXG', 'MING', "Letme"]
TEAM.push('xiaohu')
console.log(TEAM);
// ['UZI', 'MLXG', 'MING', 'Letme', 'xiaohu']
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 2.3 变量的解构赋值
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构赋值。
<script>
// ES6 允许按照一定模式从数组和对象中提取值,对变量进行赋值
// 这被称为解构赋值
// 1. 数组的结构
// 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()
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
注意:频繁使用对象方法、数组元素,就可以使用解构赋值形式
# 2.4 模板字符串
模板字符串(template string)是增强版的字符串,用反引号(`)标识,特点:
- 字符串中可以出现换行符
- 可以使用
${xxx}形式输出变量
<script>
// ES6 引入新的声明字符串的方式 [``] '' ""
// 1. 声明
// let str = `我也是一个字符串哦!`
// console.log(str, typeof str);
// 2. 内容中可以直接出现换行符
let str = `<ul>
<li>沈腾</li>
<li>玛丽</li>
<li>魏翔</li>
<li>艾伦</li>
</ul>`
// 3. 变量拼接
let lovest = '沈腾'
let out = `${lovest}是我心目中最搞笑的演员`
console.log(out);
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
注意:当遇到字符串与变量拼接的情况使用模板字符串
# 2.5 简化对象写法
ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁
<script>
// ES6 运行在大括号里面 直接写入变量和函数 座位对象的属性和方法
// 这样书写更加简洁
let name = 'boluo'
let change = function () {
console.log('我们可以改变你');
}
const school = {
name,
change,
improve() {
console.log("我们可以提高你的技能");
}
}
console.log(school);
school.improve()
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
注意:对象简写形式简化了代码,所以以后用简写就对了
# 2.6 箭头函数
ES6 允许使用「箭头」(=>)定义函数。
通用写法
/**
* 1. 通用写法
*/
let fn = (arg1, arg2, arg3) => {
return arg1 + arg2 + arg3;
}
2
3
4
5
6
箭头函数的注意点:
- 如果形参只有一个,则小括号可以省略
- 函数体如果只有一条语句,则花括号可以省略,函数的返回值为该条语句的 执行结果(return 也该省略)
- 箭头函数
this指向声明时所在作用域下this的值 - 箭头函数不能作为构造函数实例化
- 不能使用
arguments
// 1. this 是静态的 this 始终指向函数声明时所在作用域的 this 的值
function getName() {
console.log(this.name);
}
let getName2 = () => {
console.log(this.name);
}
// 设置 window 对象的 name 属性
window.name = "菠萝"
const school = {
name: "西瓜"
}
// 直接调用 这里指向 window
// getName()
// getName2()
// 1. call 方法调用
// getName.call(school) // 这里指向 school
// getName2.call(school) // 这里始终指向 window
// 2. 不能作为构造函数实例化对象
// let Person = (name, age) => {
// this.name = name
// this.age = age
// }
// let me = new Person('xiao', 30)
// console.log(me);
// 3. 不能使用 arguments 变量
// let fn = () => {
// console.log(arguments);
// }
// fn(1, 2, 3)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// 4. 箭头函数的简写
// 1 省略小括号(当形参有且只有一个的时候)
let add = n => {
return n + n
}
console.log(add(9));
// 2 省略花括号 当代码体只有一条语句的时候
// 此时 return 必须省略 而且语句执行结果就算函数的返回值
let pow = n => n * n
console.log(pow(9));
2
3
4
5
6
7
8
9
10
11
12
注意:箭头函数不会更改 this 指向,用来指定回调函数会非常合适
箭头函数实践
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>箭头函数实践</title>
<style>
div {
width: 200px;
height: 200px;
background: #58a;
}
</style>
</head>
<body>
<div id="ad"></div>
<script>
//需求-1 点击 div 2s 后颜色变成『粉色』
//获取元素
let ad = document.getElementById('ad');
//绑定事件
ad.addEventListener("click", function(){
//保存 this 的值
// let _this = this;
//定时器
setTimeout(() => {
//修改背景颜色 this
// console.log(this);
// _this.style.background = 'pink';
this.style.background = 'pink';
}, 2000);
});
//需求-2 从数组中返回偶数的元素
const arr = [1,6,9,10,100,25];
// const result = arr.filter(function(item){
// if(item % 2 === 0){
// return true;
// }else{
// return false;
// }
// });
const result = arr.filter(item => item % 2 === 0);
console.log(result);
// 箭头函数适合与 this 无关的回调. 定时器, 数组的方法回调
// 箭头函数不适合与 this 有关的回调. 事件回调, 对象的方法
</script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
函数参数的默认值设置
<script>
// ES6 允许给函数参数赋值初始值
// 1. 形参初始值 具有默认值的参数 一般位置要靠后(潜规则)
// function add(a, b, c = 10) {
// return a + b + c
// }
// let result = add(1, 2)
// console.log(result);
// 2. 与解构赋值结合
function connect({ host = '127.0.0.1', username, password, port }) {
console.log(host);
console.log(username);
console.log(password);
console.log(port);
}
connect({
host: "boluo.com",
username: 'root',
password: 'root',
port: 3306
})
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 2.7 rest 参数
ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments
<script>
// ES6 引入 rest 参数 用于获取参数的实参 用来替代 argument
// ES5 获取实参的方式
// function date() {
// console.log(arguments);
// }
// date('菠萝', '西瓜', '苹果')
// 这里是对象
// rest 参数
// function date(...args) {
// console.log(args);
// }
// date('菠萝', '西瓜', '苹果')
// 这里是数组
// rest 参数必须要放到参数最后
function fn(a, b, ...args) {
console.log(a);
console.log(b);
console.log(args);
}
fn(1, 2, 3, 4, 5)
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
注意:rest 参数非常适合不定个数参数函数的场景
# 2.8 spread 扩展运算符
扩展运算符(spread)也是三个点(...)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列,对数组进行解包。
<script>
// 扩展运算符能将 数组 转换为逗号分隔的参数序列
// 声明一个数组
const fruit = ['菠萝', '水蜜桃', '西瓜']
// 声明一个函数
function chunwan() {
console.log(arguments);
}
chunwan(...fruit[1])
// ['水', '蜜', '桃']
</script>
2
3
4
5
6
7
8
9
10
11
12
扩展运算符的应用
<body>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<script>
// 1. 数组的合并
// const kuaizi = ['王太利', '肖央']
// const fenghuang = ['曾毅', '玲花']
// const zuixuanxiaopingguo = [...kuaizi, ...fenghuang]
// console.log(zuixuanxiaopingguo[1]);
// ['王太利', '肖中', '曾毅', '玲花']
// 2. 数组的克隆 (引用数据类型 浅拷贝)
// const sanzhihua = ['E', 'G', 'M']
// const sanyecao = [...sanzhihua]
// console.log(sanzhihua);
// 3. 将伪数组转为真正的数组 可以使用 map filter every等方法
const divs = document.querySelectorAll("div")
const divArr = [...divs]
console.log(divArr);
</script>
</body>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 2.9 Symbol
# 2.9.1 Symbol 基本使用
ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型。
Symbol 特点
Symbol的值是唯一的,用来解决命名冲突的问题Symbol值不能与其他数据进行运算Symbol定义的对象属性不能使用for…in循 环遍 历 ,但 是可 以 使 用Reflect.ownKeys来获取对象的所有键名
代码示例
<script>
// 创建 Symbol
// let s = Symbol()
// console.log(s, typeof s); // Symbol() 'symbol'
// let s2 = Symbol("菠萝")
// let s3 = Symbol("菠萝")
// console.log(s2 === s3); // false
// Symbol.for 创建
// let s4 = Symbol.for("咕噜肉")
// let s5 = Symbol.for("咕噜肉")
// console.log(s4 === s5); // true
// 不能与其他数据进行运算
// let result = s + 100
// let result = s + 100
// let result = s + 100
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
注: 遇到唯一性的场景时要想到
Symbol
# 2.9.2 给对象添加 Symbol属性
方法一:
// 向对象中添加方法 up down
let game = {
}
// 声明一个对象
let methods = {
up: Symbol(),
down: Symbol()
}
game[methods.up] = function () {
console.log("我可以改变形状");
}
game[methods.down] = function () {
console.log("我可以快速下降");
}
console.log(game);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
方法二:
let youxi = {
name: '狼人杀',
[Symbol('say')]: function () {
console.log("我可以发言");
},
[Symbol('zibao')]: function () {
console.log("我可以自爆");
}
}
console.log(youxi);
2
3
4
5
6
7
8
9
10
# 2.9.3 Symbol 内置值
除了定义自己使用的 Symbol 值以外,ES6 还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法。可以称这些方法为魔术方法,因为它们会在特定的场 景下自动执行。
Symbol.hasInstance | 当其他对象使用 instanceof 运算符,判断是否为该对 象的实例时,会调用这个方法 |
Symbol.isConcatSpreadable | 对象的 Symbol.isConcatSpreadable 属性等于的是一个 布尔值,表示该对象用于 Array.prototype.concat()时, 是否可以展开。 |
Symbol.species | 创建衍生对象时,会使用该属性 |
Symbol.match | 当执行 str.match(myObject) 时,如果该属性存在,会 调用它,返回该方法的返回值。 |
Symbol.replace | 当该对象被 str.replace(myObject)方法调用时,会返回 该方法的返回值。 |
Symbol.search | 当该对象被 str.search (myObject)方法调用时,会返回 该方法的返回值。 |
Symbol.split | 当该对象被 str.split(myObject)方法调用时,会返回该 方法的返回值。 |
Symbol.iterator | 该对象被转为原始类型的值时,会调用这个方法,返 回该对象对应的原始类型值 |
Symbol. toStringTag | 在该对象上面调用 toString 方法时,返回该方法的返 回值 |
Symbol. unscopables | 该对象指定了使用 with 关键字时,哪些属性会被 with 环境排除。 |
# 2.10 迭代器
遍历器(Iterator)就是一种机制。它是一种接口,为各种不同的数据结构提 供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。
ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of消费- 原生具备 iterator 接口的数据(可用 for of 遍历
ArrayArgumentsSetMapStringTypedArrayNodeList
- 工作原理
- 创建一个指针对象,指向当前数据结构的起始位置
- 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员
- 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员
- 每调用 next 方法返回一个包含 value 和 done 属性的对象
// 声明一个数组
const xiyou = ['唐僧', '孙悟空', '猪八戒', '沙僧']
// 使用 for of 遍历数组 for in 打印索引
for (let v of xiyou) {
console.log(v); // 打印键值
}
let iterator = xiyou[Symbol.iterator]()
// 调用对象 next 方法
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
// {value: '唐僧', done: false}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
注: 需要自定义遍历数据的时候,要想到迭代器。
# 自定义遍历数据
// 声明一个对象
const fruit = {
name: "水果",
stus: [
'西瓜',
'香蕉',
'菠萝'
],
[Symbol.iterator]() {
// 索引变量
let index = 0
return {
next: () => {
if (index < this.stus.length) {
const result = { value: this.stus[index], done: false }
// 下标自增
index++
// 返回结果
return result
} else {
return { value: undefined, done: true }
}
}
}
}
}
// 遍历这个对象
for (let v of fruit) {
console.log(v);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 2.11 生成器
生成器函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同
代码说明:
*的位置没有限制- 生成器函数返回的结果是迭代器对象,调用迭代器对象的
next方法可以得到yield语句后的值 yield相当于函数的暂停标记,也可以认为是函数的分隔符,每调用一次next方法,执行一段代码next方法可以传递实参,作为yield语句的返回值
代码演示 1
// 生成器其实就是一个特殊函数
// 异步编程 纯回调函数 node fs ajax mongodb
// yield 函数代码的分隔符
function* gen() {
// console.log(111);
yield '一只没有耳朵'
// console.log(222);
yield '一只没有尾巴'
// console.log(333);
yield '真奇怪'
}
let iterator = gen()
// iterator.next() // 111
// iterator.next() // 222
// iterator.next() // 333
console.log(iterator.next()); // {value: '一只没有耳朵', done: false}
console.log(iterator.next()); // {value: '一只没有尾巴', done: false}
console.log(iterator.next()); // {value: '真奇怪', done: false}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
代码演示 2
function* gen(arg) {
console.log(arg);
let one = yield 111;
console.log(one);
let two = yield 222;
console.log(two);
let three = yield 333;
console.log(three);
}
//执行获取迭代器对象
let iterator = gen('AAA');
console.log(iterator.next());
//next方法可以传入实参
console.log(iterator.next('BBB'));
console.log(iterator.next('CCC'));
console.log(iterator.next('DDD'));
// AAA
// {value: 111, done: false}
// BBB
// {value: 222, done: false}
// CCC
// {value: 333, done: false}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
生成器函数实例1(解决回调地狱问题)
// 异步编程 文件操作 网络操作(ajax request) 数据库操作
// 1s 后控制输出 111 2s输出 222 3秒后 输出 333
// 回调地狱
// setTimeout(() => {
// console.log(111);
// setTimeout(() => {
// console.log(222);
// setTimeout(() => {
// console.log(333);
// }, 3000)
// }, 2000)
// }, 1000)
function one(value, mm) {
setTimeout(() => {
console.log(value);
iterator.next()
}, mm);
}
function* gen() {
yield one(111, 1000)
yield one(222, 2000)
yield one(333, 3000)
}
// 调用生成器函数
let iterator = gen()
iterator.next()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
生成器函数实例 2
// 模拟获取 用户数据 订单数据 商品数据
function getUsers() {
setTimeout(() => {
let data = '用户数据'
// 调用 next 方法 并且将数据传入
iterator.next(data)
}, 1000);
}
function getOrders() {
setTimeout(() => {
let data = '订单数据'
iterator.next(data)
}, 1000);
}
function getGoods() {
setTimeout(() => {
let data = '商品数据'
iterator.next(data)
}, 1000);
}
function* gen() {
let users = yield getUsers()
console.log(users);
let orders = yield getOrders()
console.log(orders);
let goods = yield getGoods()
console.log(goods);
}
let iterator = gen()
iterator.next()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 2.12 Promise
Promise 是 ES6 引入的异步编程的新解决方案。语法上 Promise 是一个构造函数, 用来封装异步操作并可以获取其成功或失败的结果。
代码示例
// 实例化 Promise 对象
const p = new Promise(function (resolve, reject) {
setTimeout(() => {
// let data = "数据库中的用户数据"
// resolve
// resolve(data)
let err = '数据读取失败'
reject(err)
}, 1000);
})
// 调用 promise 对象的 then 方法
p.then(function (value) {
console.log(value);
}, function (reason) {
console.error(reason)
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
未完待续...