1. 概述
ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
Q1:ECMAScript 和 JavaScript 的关系?
ECMAScript 和 JavaScript 的关系是,前者是后者的规范,后者是前者的一种实现(另外的 ECMAScript 方言还有 Jscript 和 ActionScript)。
Q2:ES6 与 ECMAScript 2015?
2011 年,ECMAScript 5.1 版发布后,就开始制定 6.0 版了。因此,ES6 这个词的原意,就是指 JavaScript 语言的下一个版本。
ES6 的第一个版本,在 2015 年 6 月发布,正式名称是《ECMAScript 2015 标准》(简称 ES2015)。
2016 年 6 月,小幅修订的《ECMAScript 2016 标准》(简称 ES2016)如期发布,这个版本可以看作是 ES6.1 版,因为两者的差异非常小,基本上是同一个标准。根据计划,2017 年 6 月发布 ES2017 标准。
因此,ES6 既是一个历史名词,也是一个泛指,含义是 5.1 版以后的 JavaScript 的下一代标准,涵盖了 ES2015、ES2016、ES2017 等等,而 ES2015 则是正式名称,特指该年发布的正式版本的语言标准。本书中提到 ES6 的地方,一般是指 ES2015 标准,但有时也是泛指“下一代 JavaScript 语言”。
2. 基本语法
ES 标准中不包含 DOM 和 BOM 的定义,只涵盖基本数据类型、关键字、语句、运算符、内建对象、内建函数等通用语法。
本部分只学习前端开发中 ES6 的最少必要知识,方便后面项目开发中对代码的理解。
开发工具 VSCode
- 安装插件:Chinese、Live Server、Vetur、vue-helper
- 在本地新建文件夹
- [VSCode] 文件 → 打开文件夹
- [VSCode] 文件 → 将工作区另存为 → 保存在自己创建的文件夹下,随便取个名字(后缀是 .code-workspace)
- 以服务器方式打开网页预览:安装 Live Server 插件,然后文件右键 Open with Live Server
2.1 let、const
1. let 声明变量
// 1. let 有作用域的概念
{
var a = 100;
// let b = 1101;
}
console.log(a); // 100
// console.log(b); // b is not defined
// 2. let 不可重复声明同名变量
var c = 200;
var c = 222;
console.log(c); // 222
let d = 300;
// let d = 333;
// console.log(d); // redeclaration of let d
// 3. var 会提升变量声明,let 不会
// console.log(e);
// var e = 400; // undefined
// let e = 400; // can't access lexical declaration 'e' before initialization
2. const 声明常量
const PI = 3.14;
console.log(PI);
// 1. const 声明的变量,一经定义不能改变
// PI = 3; // invalid assignment to const 'PI'
// 2. const 声明时必须赋值
// const PI2; // missing = in const declaration
2.2 解构赋值
解构赋值是对赋值运算符的扩展。它是一种针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。
// 1. 解构数组进行变量赋值
// ----- common
let a = 1, b = 2, c = 3;
console.log(a, b, c);
// ----- ES6
let [x, y, z] = [1, 2, 3];
console.log(x, y, z);
// 2. 解构对象赋值:变量名和字段名要一一对应
let user = {name: 'liuyuan', age: 22};
// ----- common
let name1 = user.name;
let age1 = user.age;
console.log(name1);
console.log(age1);
// ----- ES6
let {name:newName, age} = user;
console.log(name); // <empty string>
console.log(newName); // user.name->name->newName
console.log(age);
2.3 模板字符串
模板字符串相当于加强版的字符串,用反引号 `,除了作为普通字符串,还可以用来定义多行字符串,还可以在字符串中加入变量和表达式。
let str1 = 'Hello';
let str2 = 'How are you';
console.log(str1 + '!' + str2 + "?");
// 1. 字符串插入变量和表达式
console.log(`${str1}!${str2}?`); // Hello!How are you?
// 2. 字符串中调用函数
function getName() {
return 'root';
}
console.log(`${str1}!${getName()}!`); // Hello!root!
// 3. 多行字符串
let headContent = `
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
`;
console.log(headContent);
2.4 声明对象简写
let name = 'tree';
let age = 13;
// 传统
let user = {name: name, age: age};
console.log(user);
// 声明对象简写
let user2 = {name, age};
console.log(user2);
2.5 声明方法简写
// 定义函数
function f1 () {}
let f2 = function() {};
// 定义方法
let user = {
name: 'tree',
age: 13,
// sayHi: function() {
sayHi() {
console.log(this.name + "say Hi!");
}
};
user.sayHi();
2.6 对象拓展运算符
拓展运算符 ...
用于取出参数对象所有可遍历属性然后拷贝到当前对象。
// 1. 对象复制
let user = {name: 'tree', age: 13};
let someone1 = user; // 指向同一个对象
someone1.name = 'tree1';
console.log(someone1); // Object { name: "tree1", age: 13 }
console.log(user); // Object { name: "tree1", age: 13 }
let someone2 = {...user}; // ~ COPY 一个对象赋值给 someone2
someone2.name = 'tree2';
console.log(someone2); // Object { name: "tree2", age: 13 }
console.log(user); // Object { name: "tree1", age: 13 }
// 2. 合并对象
let name = {name: 'tree3'};
let age = {age: 22};
let someone3 = {...name, ...age};
console.log(someone3);
let someone4 = {...someone2, ...someone3};
// 合并的对象中字段有交集,会覆盖重名变量
console.log(someone4); // Object { name: "tree3", age: 22 }
2.7 函数的默认参数
只有在未传递参数,或者参数为 undefined 时,才会使用默认参数;null 值被认为是有效的值传递。
function getUser(name, age = 18) {
console.log(name, age);
}
getUser('tree', 22); // tree 22
getUser('tree', ''); // tree <empty string>
getUser('tree', null); // tree null
getUser('tree'); // tree undefined [设置默认值后] tree 18
2.8 不定参数
不定参数用来表示不确定参数个数,形如 ...变量名
,由 ...
加上一个具名参数标识符组成。具名参数只能放在参数列表的最后,并且有且只有一个不定参数。
function f1 (...values) {
console.log(values.length); // 5
console.log(values); // Array(5) [ 1, 2, 3, 4, 5 ]
}
f1(1, 2, 3, 4, 5);
2.9 箭头函数
// 基本语法:参数 => 函数体
// - 当箭头函数体有多行语句,用 {} 包裹起来,表示代码块。
// - 当箭头函数没有参数或者有多个参数,要用 () 括起来,单个参数可省。
// - 当只有一行语句,并且需要返回结果时,可以省略 {} , 结果会自动返回。
let f1 = function(a) {
return a;
};
let f2 = (a)=>{return a;};
let f3 = a=>a*3;
let f4 = a=>console.log(a);
let f5 = ()=>console.log('神似 Lambda');
/*
* 一般用在回调函数上
* $.get('url', data => {
*
* })
*/
3. Promise
在 JavaScript 的世界中,所有代码都是单线程执行的。由于这个“缺陷”,导致 JavaScript 的所有网络操作,浏览器事件,都必须是异步执行。
1. 准备数据
[mock/user.json]
{
"id": "1",
"username":"helen",
"age":18
}
[user-1-login-log.json]
{
"items": [
{"id": 1, "time": "2017"},
{"id": 1, "time": "2018"},
{"id": 1, "time": "2019"}
]
}
2. 异步执行可以用回调函数实现
// (1) timeout的定时器功能使用了回调函数
console.log('before setTimeout()');
setTimeout(()=>{
console.log('Done')
}, 1000) // 1s后调用callback函数
console.log('after setTimeout()');
·········································
// html页面引入jquery.js
<script src="jquery.min.js"></script>
// (2) Ajax功能使用了回调函数
$.get('mock/user.json', (data)=>{
console.log(data);
})
3. 1s 后执行 ajax 操作
// (1) timeout的定时器功能使用了回调函数
console.log('before setTimeout()')
setTimeout(() => {
// (2) ajax功能使用了回调函数
$.get('mock/user.json', (data) => {
console.log(data)
})
}, 1000); // 1s后调用callback函数
console.log('after setTimeout()')
4. 1s后获取用户数据,然后根据用户 id 获取用户登录日志
console.log('before setTimeout()')
setTimeout(() => { // (1) 1s后获取用户数据
console.log('Done')
$.get('mock/user.json', (data) => { // (2) 获取用户数据
console.log(data)
$.get(`mock/user-${data.id}-login-log.json`, (data) => { // (3) 获取当前用户的登录日志
console.log(data)
})
})
}, 1000)
console.log('after setTimeout()')
Promise 是异步编程的一种解决方案。从语法上说,Promise 是一个对象,从它可以获取异步操作的响应消息。
5. 只考虑成功情况的 Promise 对象
var p1 = new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve() // 成功后交给 resolve 去执行回调的内容
}, 1000)
})
p1.then(()=>{ // 成功
// 因为还有后续动作,所以接着返回 promise 对象
return new Promise((resolve, reject)=>{
$.get(`mock/user.json`, (data) => {
resolve(data)
})
})
}).then((data)=>{ // 成功
console.log(data)
$.get(`mock/login-log-${data.id}.json`, (data) => {
console.log(data)
})
// 如果之后还有后续动作,那么接着返回 promise 对象
})
6. 有错误处理的 Promise
// 3s后输出信息
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('== 3s后执行的代码 ==');
resolve(); // 类似于接口方法
}, 3000);
});
p1.then(()=>{
return new Promise((resolve, reject)=>{
$.ajax({
url: 'mock/user1.json',
type: 'get',
success(data) {
console.log(data);
resolve(data);
},
error(error) {
reject(error);
}
});
});
}).then((data) => {
$.get(`mock/user-${data.id}-login-log.json`, data => {
console.log(data);
});
// }, error => {
}).catch(error=>{ // 使用 catch 处理失败
console.log("查询失败!");
});