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-

posted @ 2023-07-26 17:11  SRIGT  阅读(17)  评论(0编辑  收藏  举报