ES6~ES9
ES6
1. let
1.1 let 变量声明及声明特性
let 用来声明变量,具有以下特性:
一、相较于 var ,let 变量不能重复声明
let a = 'a';
let a = 'a'; // 此时会报错
二、块级作用域(es5 中共有三种作用域:全局、函数、eval),即 let 定义的变量只在块级作用域内有效
{
let a = 'a';
}
console.log(a); // is not defined
三、不存在变量提升
console.log(a); // cannot access 'a' before initialization
let a = 'a';
四、不影响作用域链
{
let a = 'a';
function func(){
console.log(a);
}
func();
}
1.2 let 经典案例实践
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>切换颜色</title>
<style>
body{
margin: 0;
padding: 0;
background: #ccc;
}
h2{
margin: 10px;
font-size: 40px;
}
.item{
display: flex;
float: left;
margin: 20px;
border: 2px solid #000;
width: 200px;
height: 100px;
background: #fff;
}
</style>
</head>
<body>
<h2>
点击切换颜色
</h2>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<script>
var items = document.getElementsByClassName('item');
/*
for(var i = 0; i < items.length; i++){
items[i].onclick = function(){
this.style.background = 'pink';
}
}
*/
//使用 let 代替上述 Code
for(let i = 0; i < items.length; i++){
items[i].onclick = function(){
items[i].style.background = 'pink';
}
}
</script>
</body>
</html>
2. const
2.1 const 变量声明及声明特性
一、必须要赋初始值
二、一般常量使用大写(非必须)
三、常量的值不能修改
四、块级作用域
五、对于数组和对象的元素修改不算对常量的修改,不会报错
const TEAM = ['a', 'b'];
TEAM.push('c');
// TEAM = 100; 这句话会报错
3.变量的解构赋值
ES6 允许按照一定模式从数组和对象中提取一些值,对变量进行赋值
3.1数组的解构
const arr = ['a', 'b', 'c', 'd'];
// 定义四个变量,依次对应上面数组的值
let [A, B, C, D] = arr;
console.log(A);
console.log(B);
console.log(C);
console.log(D);
3.2对象的解构
const obj = {
str: 'abc',
num: 25,
fun: function(){
console.log("Output");
}
}
// 与上面的 Code 格式相同,都要使用花括号
let {str, num, fun} = obj;
console.log(str);
console.log(num);
console.log(fun);
fun();
/*
let {fun} = obj;
fun();
*/
4.模板字符串
一、声明上,相比 ES5,ES6 引入了新的字符串声明符号——反引号,与单双引号区别不大。
二、反引号中的内容可以直接出现换行符,举例,
let str = `abc
def
ghi`;
console.log(str);
三、变量拼接
let s1 = "Hello,";
let s2 = `${s1}World!`;
console.log(s2);
5.对象的简化写法
ES6 允许在大括号里面直接写入变量和函数,作为对象的属性和方法。
let name = "user";
let func = function(){
console.log("abc");
}
const obj = {
name,
func
}
console.log(obj);
还有方法声明的简化,
const obj1 = {
name: "abc",
improve: function(){
console.log("abc");
}
}
// 以下为简化版
const obj2 = {
name: "def",
improve(){
console.log("def");
}
}
6.箭头函数
6.1箭头函数及声明特点
ES6 允许使用箭头(=>)定义函数。
let func = (a, b) => {
return a + b;
}
func(1, 1);
箭头函数的特性:
一、this 是静态的,始终指向函数声明时所在作用域下的 this 的值。
function getName1(){
console.log(this.name);
}
let getName2 = () => {
console.log(this.name);
}
window.name = "abc";
const obj = {
name: "def"
}
// 直接调用函数
getName1(); //> abc
getName2(); //> abc
//call 方法调用
getName1.call(obj); //> def
getName2.call(obj); //> abc
二、不能作为构造函数实例化对象
let Person = (name, age) => {
this.name = name;
this.age = age;
}
let me = new Person('abc', 20);
console.log(me); // 报错
三、不能使用 arguments 变量(该变量一般用来保存实参)
四、箭头函数简写
(1)当形参有且仅有一个时,可以省略小括号;
let add = n => {
return n + n;
}
console.log(add(1));
(2)当代码体仅有一条语句时,可以同时省略花括号和 return 语句;
let pow = n => n*n;
console.log(pow(2));
6.2箭头函数的实践与应用
例一,点击 div 2s 后变色
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
body{
margin: 0;
padding: 0;
background: #ccc;
}
div{
width: 200px;
height: 200px;
background: #58a;
}
</style>
</head>
<body>
<div id="ad"></div>
<script>
let ad = document.getElementById('ad');
ad.addEventListener("click", function(){
/* 方法一
let _this = this;
setTimeout(function(){
_this.style.background = 'pink';
}, 2000);
*/
setTimeout(() => {
this.style.background = 'pink';
}, 2000);
});
</script>
</body>
</html>
例二,从数组中返回偶数元素
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
body{
margin: 0;
padding: 0;
background: #ccc;
}
div{
width: 200px;
height: 200px;
background: #58a;
}
</style>
</head>
<body>
<div id="ad"></div>
<script>
let ad = document.getElementById('ad');
ad.addEventListener("click", function(){
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);
});
</script>
</body>
</html>
由此可得以下结论,
一、箭头函数适合与 this 无关的回调(定时器、数组等)
二、箭头函数不适合与 this 有关的回调(DOM 事件回调、对象方法等)
7.函数参数的默认值设置
7.1形参的初始值
function add(a, b, c){
return a + b + c;
}
let result1 = add(1, 2);
console.log(result1); //> NaN
function sub(a, b, c = 10){
return c - b - a;
}
let result2 = sub(1, 2);
console.log(result2); //> 7
带默认参数的函数的位置一般靠后。
7.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: 'localhost',
username: 'root',
password: 'root',
port: 3306
})
8. rest 参数
ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments,
function date1(){
console.log(arguments);
}
date('abc','def','ghi'); // 对象
function date2(...args){
console.log(args);
}
date('abc','def','ghi'); // 数组
利用 rest 创造的数组就可以使用与数组相关的 API 方法,如 filter,some,every,map 等。
rest 参数必须要放到参数的最后,例如,
function fun(a, b, ...args){
console.log(a); //> 1
console.log(b); //> 2
console.log(args); //> [3, 4, 5, 6]
}
fun(1, 2, 3, 4, 5, 6);
9.扩展运算符( ... )
扩展运算符 ... 能将数组转换为逗号分隔的参数序列
const arr = ['abc', 'def', 'ghi'];
function fun(){
console.log(arguments);
}
fun(arr); //> 0: ['abc', 'def', 'ghi']
fun(...arr); //> 0: 'abc' 1: 'def' 2: 'ghi'
应用:
一、数组的合并
const arr1 = ['abc', 'def'];
const arr2 = ['123', '456'];
//ES5
const arr3 = arr1.concat(arr2);
console.log(arr3);
//ES6
const arr4 = [...arr1, ...arr2];
console.log(arr4);
二、数组的克隆
const arr1 = ['abc', 'def'];
const arr2 = [...arr1];
-----》(引用数据问题?)《-----
三、将伪数组转换为真正的数组
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div></div>
<div></div>
<div></div>
<script>
const divs = document.querySelectorAll('div')
console.log(divs); // 对象
const divArr = [...divs];
console.log(divArr); // 数组
</script>
</body>
</html>
10. Symbol 数据类型
ES6 引入了一种新的原始数据类型——Symbol,用来表示独一无二的值。
它是 JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型。
10.1特点
一、Symbol 的值是唯一的,用来解决命名冲突问题
二、Symbol 的值不能与其他数据进行运算
三、Symbol 定义的对象属性不能使用 for...in 循环遍历,但是可以使用 Reflect.ownKeys 来获取对象的所有键名
10.2创建 Symbol
// 方法一,此时 Symbol 是一个函数
let s1 = Symbol();
console.log(s1, typeof s1); //> Symbol() 'symbol'
let s2 = Symbol('abc');
let s3 = Symbol('abc');
console.log(s2 === s3); //> false
// 方法二,此时 Symbol 是一个对象
let s4 = Symbol.for('abc');
console.log(s4, typeof s4); //> Symbol(abc) 'symbol'
let s5 = Symbol.for('abc');
let s6 = Symbol.for('abc');
console.log(s5 === s6); //> true
总结:JavaScript 的七种数据类型 “USONB”
U:undefined S:string symbol O:object N:null number B:boolean
10.3给对象添加 Symbol 类型的属性
let obj = {
name: 'abc'
};
let ud = {
up: Symbol(),
down: Symbol()
};
obj[ud.up] = function(){
console.log("up");
}
obj[ud.down] = function(){
console.log("down");
}
let obj = {
name: 'abc',
[Symbol('say')]: function(){
console.log("def");
},
[Symbol('sby')]: function(){
console.log("ghi");
}
}
console.log(obj);
10.4 Symbol 内置值
所谓内置值,即为 Symbol 对象的属性(共 11 个)。
内置值 | 描述 |
---|---|
Symbol.hasInstance | 当其他对象调用 instanceof 运算符,判断是否为该对象的实例时,回调用这个方法 |
Symbol.isConcatSpreadable | 对象的该属性等于的是一个布尔值,表示该对象用于 Array.prototype.concat() 时,是否可以展开 |
Symbol.unscopables | 该对象指定了使用 with 关键字时,哪些属性会被 with 环境排除 |
Symbol.match | 当执行 str.match(myObject) 时,如果该属性存在,会调用它,返回该方法的返回值 |
Symbol.replace | 当该对象被 str.replace(Object) 方法调用时,会返回该方法的返回值 |
Symbol.search | 当该对象被 str.search(Object) 方法调用时,会返回该方法的返回值 |
Symbol.split | 当该对象被 str.split(Object) 方法调用时,会返回该方法的返回值 |
Symbol.iterator | 对象进行 for...of 循环时,会调用 Symbol.iterator 方法,返回该对象的默认遍历器 |
Symbol.toPrimitive | 该对象被转为原始类型的值,会调用这个方法,返回该对象对应的原始类型值 |
Symbol.toStringTag | 在该对象上面调用 toString 方法时,返回该方法的返回值 |
Symbol.species | 创建衍生对象时,会使用该属性 |
10.4.1 Symbol.hasInstance
class Person{
static [Symbol.hasInstance](param){
console.log(param);
console.log("abc"); //> abc
//return true;
}
}
let o = {};
console.log(o instanceof Person); //> false
10.4.2 Symbol.isConcatSpreadable
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
arr2[Symbol.isConcatSpreadable] = false; //不可展开
const arr3 = arr1.concat(arr2);
console.log(arr3); //> [1, 2, 3, [4, 5, 6]]
console.log(arr3.length); //> 4
11.迭代器
迭代器(Iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。
任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。
12.生成器
13. Promise*
Promise 是 ES6 引入异步编程的新解决方案。
语法上,Promise 是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。
(关于异步编程,主要指的是 IO 的代码,包括文件IO、数据库IO、网络请求IO等)
13.1实例化 Promise 对象
对象的三种状态:初始化,成功,失败。
const p = new Promise(function(resolve, reject){
// 封装异步操作
setTimeout(function(){
let data = '数据库中的用户数据';
resolve(data);
let err = '数据读取失败';
reject(err);
}, 1000);
});
// 调用 Promise 对象的 then 方法
p.then(function(value){
// 异步成功执行
console.log(value);
}, function(reason){
// 异步失败执行
console.error(reason);
});
13.2使用 Promise 封装读取文件
(注:涉及 Node.js)
// 1.引入 fs 模块
const fs = require('fs');
// 2.调用方法
fs.readFile('./aha/aaa.md', (err, data)=>{
//err:报错 data:读取结果
if(err) throw err;
console.log(data); //> <Buffer 61 61 61 09 e4 b8 80 e4 ba 8c e4 b8 89>
console.log(data.toString()); //> aaa 一二三
});
// 3.使用 Promise 封装
const p = new Promise(function(resolve, reject){
fs.readFile("./aha/aaa.md", (err, data)=>{
if(err) reject(err);
resolve(data);
});
});
p.then(function(value){
console.log(value.toString()); //> aaa 一二三
}, function(reason){
console.log("读取失败!!");
});
(上述 Code 在 PowerShell 中,使用 node FileName.js 命令调试)
13.3使用 Promise 封装 Ajax 请求
const p = new Promise((resolve, reject)=>{
// 1.创建对象
const xhr = new XMLHttpRequest();
// 2.初始化
xhr.open("GET", "https://api.apiopen.top/getJoke");
// 3.发送
xhr.send();
// 4.绑定事件,处理响应结果
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
// 判断响应状态码 200-299表示成功
if(xhr.status >= 200 && xhr.status < 300){
resolve(xhr.response);
}else{
reject(xhr.status);
}
}
}
});
// 指定回调
p.then(function(value){
console.log(value);
}, function(reason){
console.err(reason);
});
13.4 Promise.prototype.then 方法
const p = new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve('用户数据');
}, 1000)
});
// 调用 then 方法
const result = p.then(value => {
console.log(value);
}, reason => {
console.log(reason);
});
console.log(result);
then 方法的返回结果是 Promise 对象,对象状态由回调函数的执行结果决定。
一、如果回调函数中返回结果是非 Promise 类型的数据,此时状态为成功。
二、如果是 Promise 对象,则按该 Promise 的情况返回成功或失败。
三、抛出(throw)错误,此时状态为失败。
此时说明 then 方法可以链式调用。
13.5实践练习
多文件读取。
const fs = require("fs");
fs.readFile('./aaa.aaa', (err, data1)=>{
fs.readFile('./bbb.bbb', (err, data2)=>{
fs.readFile('./ccc.ccc', (err, data3)=>{
let result = `${data1}\r\n${data2}\r\n${data3}`;
console.log(result);
});
});
});
// 使用 Promise 实现
const p = new Promise((resolve, reject) => {
fs.readFile("./aaa.aaa", (err, data) => {
resovle(data);
});
});
p.then(value => {
console.log(value.toString());
return new Promise((resolve, reject) => {
fs.readFile("./bbb.bbb", (err, data) => {
resolve([value, data]);
});
})
}).then(value => {
console.log(value.toString());
return new Promise((resolve, reject) => {
fs.readFile("./ccc.ccc", (err, data) => {
// 压入
value.push(data);
resolve(value);
});
})
}).then(value => {
console.log(value.join('\r\n'));
})
13.6 catch 方法
const p = new Promise((resolve, reject) => {
setTimeout(() => {
reject("ERROR");
}, 1000)
});
p.then(function(value){
console.log(value);
}, function(reason){
console.err(reason);
})
p.catch(function(reason){
console.warn(reason);
})
14. Set
14.1集合 Set 的创建与方法
ES6 提供了新的数据结构——Set(集合),它类似于数组,但成员的值是唯一的。
集合实现了 iterator 接口,所有可以使用扩展运算符与for...of遍历。
方法 | 描述 |
---|---|
size | 返回集合的元素个数 |
add | 增加一个新元素并返回当前集合 |
delete | 删除元素并返回当前集合 |
has | 检测集合中是否包含某个元素并返回 boolean 值 |
clear | 清空当前集合并返回 undefined |
let s = new Set();
console.log(typeof s); //> 'object'
// Set 内可传入数组或可迭代数据
let s2 = new Set(['abc', 'def', 'abc']);
console.log(s2); //> {'abc', 'def'} (会自动去重)
console.log(s2.size); //> 2
s2.add('ghi');
console.log(s2); //> {'abc', 'def', 'ghi'}
s2.delete('abc');
console.log(s2); //> {'def', 'ghi'}
console.log(s2.has('def')); //> true
s2.clear();
console.log(s2); //> undefined
let s3 = new Set(['123', '456', '789']);
// 遍历集合
for(let v of s3){
console.log(v);
}
14.2集合 Set 的实践
14.2.1数组去重
let arr = [1, 2, 3, 4, 5, 2, 1];
let res = [...new Set(arr)];
console.log(res); //> [1, 2, 3, 4, 5]
14.2.2交集
let arr1 = [1, 2, 3, 4];
let arr2 = [8, 2, 9, 8];
/*
let res = [...new Set(arr1)].filter(item => {
let s2 = new Set(arr2);
if(s2.has(item)){
return true;
}else{
return false;
}
});
console.log(res); //> [2]
*/
let res = [...new Set(arr1)].filter(item => new Set(arr2).has(item));
console.log(res); //> [2]
14.2.3并集
let arr1 = [1, 2, 4];
let arr2 = [3, 5, 6];
let union = [...new Set([...arr1, ...arr2])];
console.log(union); //> [1, 2, 4, 3, 5, 6]
14.2.4差集
let arr1 = [1, 2, 3];
let arr2 = [1, 2, 4];
let res = [...new Set(arr1)].filter(item => !(new Set(arr2).has(item)));
console.log(res); //> [3]
15. Map
ES6 提供了 Map 数据结构,它类似于对象,也是键值的集合。
“键”的范围不局限于字符串。
Map 也实现了 iterator 接口,所有可以使用扩展运算符与for...of遍历。
方法 | 描述 |
---|---|
size | 返回 Map 的元素个数 |
set | 增加一个新元素,返回当前 Map |
get | 返回键名对象的键值 |
has | 检测 Map 中是否包含某个元素并返回 boolean 值 |
clear | 清空 Map 内所有元素并返回 undefined |
let m = new Map();
// 添加元素
m.set('name', 'abc');
m.set('change', function(){
console.log("123");
});
let key = {
school: 'def'
};
m.set(key, ['A', 'B']);
console.log(m);
// 元素个数
console.log(m.size); //> 3
// 删除元素
m.delete('name');
console.log(m);
// 获取
console.log(m.get(key));
// 遍历
for(let v of m){
console.log(v);
}
// 清空
m.clear();
16. Class
17.数值扩展
17.1 Number.EPSILON
Number.EPSILON 是 JavaScript 表示的最小精度
console.log(0.1 + 0.2 === 0.3); //> false
function equal(a, b){
if(Math.abs(a - b) < Number.EPSILON){
return true;
}else{
return false;
}
}
console.log(equal(0.1 + 0.2, 0.3)); //> true
17.2二、八、十、十六进制
//二进制
let b = 0b1010;
console.log(b); //> 10
//八进制
let o = 0o1010;
console.log(o); //> 520
//十进制
let d = 1010;
console.log(d); //> 1010
//十六进制
let x = 0x1010;
console.log(x); //> 4112
17.3 Number.isFinite
Number.isFinite 检测一个数是否为有限数
console.log(Number.isFinite(100)); //> true
console.log(Number.isFinite(100/0)); //> false
17.4 Number.isNaN
Number.isNaN 检测一个数是否为 NaN
17.5字符串转整数 / 浮点数
Number.parseInt Number.parseFloat
console.log(Number.parseFloat('12.34aaa')); //> 12.34
17.6 Number.isInteger
Number.isInteger 检测一个数是否为整数
17.7 Math.trunc
Math.trunc 将数字的小数部分删除
17.8 Math.sign
Math.sign 检测一个数是正数、负数还是零
console.log(Math.sign(10)); //> 1
console.log(Math.sign(-10)); //> -1
console.log(Math.sign(0)); //> 0
18.对象方法的扩展
18.1 Object.is
Object.is 判断两个值是否完全相等
console.log(Object.is(1, 1)); //> true
console.log(Object.is(1, 2)); //> false
// 与 === 的区别
console.log(Object.is(NaN, NaN)); //> true
console.log(NaN === NaN); //> false
18.2 Object.assign
Object.assign 对象的合并
const config1 = {
host: 'localhost',
port: 3306,
user: 'name'
};
const config2 = {
host: 'xxx.com',
port: 33060
};
// config2 覆盖 config1
console.log(Object.assign(config1, config2));
/*
输出结果:
{host: 'xxx.com', port: 33060, user: 'name'}
*/
18.3关于原型对象
Object.setPrototypeOf 设置原型对象
Object.getPrototypeOf 获取原型对象
const obj1 = {
a : 'abc'
}
const obj2 = {
b : ['1', '2', '3']
}
Object.setPrototypeOf(obj1, obj2);
console.log(obj1);
console.log(Object.getPrototypeOf(obj1));
19.模块化
模块化的优势是指将一个大的程序文件,拆分成许多小文件,然后将小文件组合秋来起来。
19.1好处
(1)防止命名冲突
(2)代码复用
(3)高维护性
19.2模块化规范产品
(1)CommonJS => NodeJS、Browserify
(2)AMD => requireJS
(3)CMD => seaJS
19.3 ES6 模块化语法
19.3.1 export 和 import
模块化功能主要由两个命令构成:export 和 import。
export 命令用于规定模块的对接口。(暴露)
import 命令用于输入其他模块提供的功能。(导入)
// File name: m1.js
// 分别暴露
export let school = 'abc';
export function fun(){
console.log("output");
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<script type="module">
// 引入 m1.js 模块
import * as mdl from "./src/js/m1.js";
</script>
</body>
</html>
19.3.2暴露模块数据语法汇总
19.3.2.1分别暴露
// File name: m1.js
export let school = 'abc';
export function fun(){
console.log("output");
}
19.3.2.2统一暴露
// File name: m2.js
let school = 'abc';
function fun(){
console.log("output");
}
export { school, fun };
19.3.2.3默认暴露
// File name: m3.js
export default{
school: 'abc',
change: function(){
console.log("output");
}
}
19.3.3导入模块数据语法汇总
19.3.3.1通用导入
<script type="module">
import * as m1 from "./src/js/m1.js";
</script>
19.3.3.2解构赋值形式导入
<script type="module">
import { school, fun } from "./src/js/m1.js";
// 变量重名处理方法
// 使用 as 将重名的键取别名化处理
import { school as school2, fun } from "./src/js/m2.js";
// 导入默认暴露的方法
import { default as m3 } from "./src/js/m3.js";
</script>
19.3.3.3简便形式导入(仅针对默认暴露)
<script type="module">
import m3 from "./src/js/m3.js";
</script>
19.3.4浏览器使用 ES6 模块化方式
通过新建 JavaScript 入口文件来导入模块。
// File name: app.js
import * as m1 from "./m1.js";
<script src="./src/js/app.js" type="module">
</script>
19.3.5 babel 对 ES6 模块化代码的转换
转换:
babel src/js -d dist/js --presets=babel-preset-env
打包:
browserify dist/js/app.js -o dist/bundle.js
导入:
<script src="dist/bundle.js"></script>
19.4模块化引入 npm 包(涉及 jQuery,跳过)
npm i jquery
ES7
20. ES7 新特性
20.1 Array.Prototype.includes
includes 方法用来检测数组中是否包含某个元素并返回 boolean 值。
const a = ['a', 'b', 'c'];
console.log(a.includes('a')); //> true
console.log(a.includes('d')); //> false
20.2指数操作符
ES7 引入指数操作符( ** )用来实现幂运算,功能与 Math.pow 结果相同。
console.log(2**4); //> 16
console.log(4**0.5); //> 2
ES8
21. async 与 await
async 和 await 两种语法结合可以让异步代码像同步代码一样。
21.1 async 函数
一、async 函数的返回值为 Promise 对象
//
async function fun(){
return 'abc';
}
const result1 = fun();
console.log(result1);
//
async function fun(){
throw new Error("W");
}
const result2 = fun();
console.log(result2);
//
async function fun(){
return new Promise((resolve, reject) => {
resolve('Success');
});
}
const result3 = fun();
console.log(result3);
result3.then(value => {
console.log(value);
}, reason => {
console.log(reason);
})
(1)如果返回的结果不是一个 Promise 类型的对象,那么 Promise 的结果就是成功。
(2)当抛出错误时,Promise 就是失败。
(3)如果返回的结果是一个 Promise 类型的对象
二、Promise 对象的结果由 async 函数执行的返回值决定
21.2 await 表达式
一、await 必须写在 async 函数中
二、await 右侧的表达式一般为 Promise 对象
三、await 返回的是 Promise 成功的值
四、await 的 Promise 失败了,就会抛出异常,需要通过 try...catch 捕获处理
// 成功
const p = new Promise((resolve, reject) => {
resolve("Success");
});
async function fun(){
let result = await p;
console.log(result);
}
fun();
// 失败
const p = new Promise((resolve, reject) => {
reject("Wrong");
});
async function fun(){
try{
let result = await p;
console.log(result);
}catch(e){
console.log(e);
}
}
fun();
21.3 async 和 await 结合读取文件
const fs = require("fs");
function reada(){
return new Promise((resolve, reject) => {
fs.readFile("./aaa.aaa", (err, data) => {
if(err) reject(err);
resovle(data);
})
})
}
function readb(){
return new Promise((resolve, reject) => {
fs.readFile("./bbb.bbb", (err, data) => {
if(err) reject(err);
resovle(data);
})
})
}
function readc(){
return new Promise((resolve, reject) => {
fs.readFile("./ccc.ccc", (err, data) => {
if(err) reject(err);
resovle(data);
})
})
}
async function fun(){
let aa = await reada();
let bb = await readb();
let cc = await readc();
console.log(aa.toString());
console.log(bb.toString());
console.log(cc.toString());
}
fun();
21.4 async 和 await 封装 Ajax 请求
发送 Ajax 请求并返回 Promise 对象。
function sendAjax(url){
return new Promise((resolve, reject) => {
// 1.创建对象
const xhr = new XMLHttpRequest();
// 2.初始化
xhr.open('GET', url);
// 3.发送
xhr.send();
// 4.事件绑定
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
if(x.status >=200 && x.status < 300){
resolve(xhr.response);
}else{
reject(xhr.status);
}
}
}
})
}
// Promise then 方法测试
sendAjax("https://api.apiopen.top/getJoke").then(value => {
console.log(value);
}, reason => {
console.log(reason);
});
// async 和 await 方法测试
async function fun(){
let result = await sendAjax("https://api.apiopen.top/getJoke");
console.log(result);
}
fun();
22.对象方法扩展
22.1 Object.values
Object.values() 方法返回一个给定对象的所有可枚举属性值的数组。
const obj = {
name: 'abc',
age: 20
};
// 获取对象所有键
console.log(Object.keys(obj));
// 获取对象所有键值
console.log(Object.values(obj));
22.2 Object.entries
Object.entries() 方法返回一个给定对象自身可遍历属性 [ key , value ] 的数组。
const obj = {
name: 'abc',
age: 20
};
console.log(Object.entries(obj));
由此可以看出,该方法有利于创建 Map 数据结构。
const obj = {
name: 'abc',
age: 20
};
const m = new Map(Object.entries(obj))
console.log(m);
22.3 Object.getOwnPropertyDescriptors
该方法返回指定对象所有自身属性的描述对象。
const obj = {
name: 'abc',
age: 20
};
console.log(Object.getOwnPropertyDescriptors(obj));
const obj = Object.create(null, {
name: {
//设置值
value: 'abc',
//设置属性特性
writable: true, // 可写
configurable: true, // 可删
enumerable: true // 可枚举
}
});
console.log(Object.getOwnPropertyDescriptors(obj));
ES9
23.扩展运算符与 rest 参数
ES9 为对象提供了像数组一样的扩展运算符和 rest 参数。
function connect({host, port, ...user}){
console.log(host);
console.log(port);
console.log(user);
}
connect({
host: '127.0.0.1',
port: 3306,
username: 'root',
password: 'root'
});
const obj1 = {
a: 'a'
}
const obj2 = {
b: 'b'
}
const obj3 = {
c: 'c'
}
const tot = {...obj1, ...obj2, ...obj3};
console.log(tot);
24.正则扩展
24.1命名捕获分组
// 未进行命名捕获分组
let str = '<a href="https://www.xxx.com">xxx</a>';
// 提取 url 与标签文本
const reg = /<a href="(.*)">(.*)<\/a>/;
// 执行
const result = reg.exec(str);
console.log(result); // groups 是 undefined 状态
console.log(result[1]); //> https://www.xxx.com
console.log(result[2]); //> xxx
// 进行命名捕获分组
let str = '<a href="https://www.xxx.com">xxx</a>';
const reg = /<a href="(?<url>.*)">(?<text>.*)<\/a>/;
const result = reg.exec(str);
console.log(result); // groups 被定义
console.log(result.groups.url); //> https://www.xxx.com
console.log(result.groups.text); //> xxx
24.2反向断言
断言:判断匹配结果正确与否。
let str = 'J123aaa456bbb';
// 正向断言
const reg1 = /\d+(?=b)/;
const res1 = reg1.exec(str);
console.log(res1);
// 反向断言
const reg2 = /(?<=a)\d+/;
const res2 = reg2.exec(str);
console.log(res2);
24.3 dotAll 模式
dot 是指正则表达式中的元字符( . ),代表除换行符以外任意单个字符
let str = `
<ul>
<li>
<a>AAA</a>
<p>aaa</p>
</li>
<li>
<a>BBB</a>
<p>bbb</p>
</li>
</ul>`;
// g/s :模式修正符
// g: 全局匹配
// s: dot 匹配任意字符
const reg = /.<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/gs;
let result;
let arr = [];
while(result = reg.exec(str)){
console.log(result);
arr.push({
x: result[1],
y: result[2]
});
}
console.log(arr);
编辑于 2022/9/17
-End-