ES6-ES11的新特性

一、ES是什么?

ES 全称 EcmaScript,是脚本语言的规范,JavaScript 是 EcmaScript的一种实现,所以 ES 新特性其实指的就是 JavaScript 的新特性

1.1 ECMA-262

Ecma 国际制定了许多标准,而 ECMA-262 只是其中的一个,ECMA-262(ECMAScript)历史版本查看网址:这里

版本 时间 概述
第 1 版 1997年 制定了语言的基本语法
第 2 版 1998年 较小改动
第 3 版 1999年 引入正则、异常处理、格式化输出等。IE 开始支持
第 4 版 2007年 过于激进,未发布
第 5 版 2009年 引入严格模式、JSON,扩展对象、数组、原型、字符串、日期方法
第 6 版 2015年 模块化、面向对象语法、Promise、箭头函数、let、const、数组解构赋值 等等
第 7 版 2016年 幂运算符、数组扩展、Async/await 关键字
第 8 版 2017年 Async/await、字符串扩展
第 9 版 2018年 对象解构赋值、正则扩展
第 10版 2019年 扩展对象、数组方法
第 11版 2020年 链式操作、动态导入等
ES.next 2020+ 动态指向下一个版本

1.2 为什么要学习 ES6

  • ES6 的版本变动内容最多,具有里程碑意义;
  • ES6 加入许多新的语法特性,编程实现更简单、高效;
  • ES6 是前端发展趋势,就业必备技能

二、ES6新特性

2.1 新特性总体概括

1、let 关键字

  • 声明局部变量;

2、const关键字

  • 声明常量;

3、变量和对象的解构赋值

  • 简化变量声明;

4、模板字符串

  • 声明自带格式的字符串;

5、简化对象和函数写法

  • 简化对象和函数写法;

6、箭头函数

  • 简化函数写法;

7、ES6中函数参数的默认值

给函数的参数设置默认值;

8、rest参数

拿到实参;

9、扩展运算符

将一个数组转为用逗号分隔的参数序列;

10、Symbol

表示独一无二的值;

11、迭代器

用来遍历集合、数组等;

12、生成器

是一种异步编程解决方案;

13、Promise

非常强大的异步编程的新解决方案;

14、Set集合

类似数组,但元素不重复的集合;

15、Map集合

  • 键值对集合;

16、class类

  • 像java实体类一样声明js类;

17、数值扩展

  • 增加一些数值相关的方法等;

18、对象扩展

  • 增加一些对象相关的方法等;

19、模块化

  • 模块化、组件化;

20、Babel对ES6模块化代码转换

  • 为了适配浏览器,将更新的ES规范转换成ES5规范;

21、ES6模块化引入NPM包

  • 像导入模块一样导入npm包;

2.2 let关键字

特性:

  1. 不允许重复声明;

  2. 块级作用域(局部变量);

  3. 不存在变量提升;

  4. 不影响作用域链;

声明代码示例:

// let关键字使用示例: let a; // 单个声明
let b,c,d; // 批量声明
let e = 100; // 单个声明并赋值
let f = 521, g = 'iloveyou', h = []; // 批量声明并赋值

1. 不允许重复声明

// 1. 不允许重复声明;
let dog = "狗"; 
let dog = "猫";
// 报错:Uncaught SyntaxError: Identifier 'dog' has already been declared

运行结果:
image-20220225154111394

2. 块儿级作用域(局部变量)

// 2. 块级作用域(局部变量);
{
    
    
  let cat = " 猫 "; console.log(cat);
}
console.log(cat);
// 报错:Uncaught ReferenceError: cat is not defined

3. 不存在变量提升

什么是变量提升:

就是在变量创建之前使用(比如输出:输出的是默认值),let不存在,var存在;

// 3. 不存在变量提升;
// 什么是变量提升:就是在变量创建之前使用(比如输出:输出的是默认值),let不存在,var存在;
console.log(people1); // 可输出默认值
console.log(people2); // 报错:Uncaught ReferenceError: people2 is not defined
var people1 = "大哥"; // 存在变量提升
let people2 = "二哥"; // 不存在变量提升

4. 不影响作用域链

什么是作用域链:就是代码块内有代码块,跟常规编程语言一样,上级代码块中的局部变量下级可用

// 4. 不影响作用域链;
{
    
    
    let p = "大哥"; 
    function fn(){
    
    
    	console.log(p); // 这里是可以使用的
    }
    fn();
}

2.3 const关键字

const 关键字用来声明常量,const 声明有以下特点:

  1. 声明必须赋初始值;

  2. 标识符一般为大写(习惯);

  3. 不允许重复声明;

  4. 值不允许修改;

  5. 块级作用域(局部变量);

2.4 变量和对象的解构赋值

什么是解构赋值:

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构赋值

// ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构赋值;
// 1、数组的解构赋值
const F4 = ["大哥","二哥","三哥","四哥"]; 
let [a,b,c,d] = F4;
// 这就相当于我们声明4个变量a,b,c,d,其值分别对应"大哥","二哥","三哥","四哥" 
console.log(a + b + c + d); // 大哥二哥三哥四哥

// 2、对象的解构赋值
const F3 = {
    
    
    name : "大哥", age : 22,
    sex : "男",
    xiaopin : function(){
    
     // 常用
        console.log("我会演小品!");
    }
}
let {
    
    name,age,sex,xiaopin} = F3; // 注意解构对象这里用的是{} 
console.log(name + age + sex + xiaopin); // 大哥22男
xiaopin(); // 此方法可以正常调用

2.5 模板字符串

模板字符串(template string)是增强版的字符串,用反引号(`)标识,特点:

  • 字符串中可以出现换行符;
  • 可以使用 ${} 形式引用变量来实现变量拼接
let s = "大哥";
let out = `${
      
      s}是我最大的榜样!`;
console.log(out); //'大哥是我最大的榜样!'

2.6 简化对象和函数写法

如果属性名和变量名相同,ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁;

// ES6允许在对象的大括号内直接写入变量和函数作为对象的属性和方法
// 变量和函数
let name = "hhhh";
let change = function(){
    
    
	console.log("活着就是为了改变世界!");
}
//创建对象
const school = {
    
    
    // 完整写法
    // name:name,
    // change:change
    // 简化写法
    name, 
    change,
    // 声明方法的简化
    say(){
    
    
    console.log("言行一致!");
    }
}
school.change(); 
school.say();

2.7 箭头函数

ES6允许使用箭头(=>)定义函数,箭头函数提供了一种更加简洁的函数书写方式,箭头函数多用于匿名函数的定义

箭头函数的重要特性

  1. 箭头函数的this是静态的,始终指向函数声明时所在作用域下的 this 的值(外层作用域);

  2. 不能作为构造函数实例化对象;

  3. 不能使用 arguments 变量;

  4. 如果形参只有一个,则小括号可以省略;

  5. 函数体如果只有一条语句,则花括号可以省略,且return也必须省略,该条语句的执行结果就是函数的返回值;

  6. 没有原型对象,没有prototype属性

// 箭头函数声明1:无参数
let speak = () => console.log("hello 哈哈!"); 
speak();
// 箭头函数声明2:一个参数
let hi = name => "hi " + name;
console.log(hi("訾博"));
// 箭头函数声明3:多个参数
let he = (a,b,c) => a + b + c;
console.log(he(1,2,3));

// 箭头函数的重要特性
// 1、箭头函数的this是静态的,始终指向函数声明时所在作用域下的this的值
const school = {
    
    
	name : "dada",
}
window.name = "小小";
// 传统函数
function getName(){
    
     
    console.log(this.name);
}
// 箭头函数
getName1 = () => {
    
    
    console.log(this.name); 
}
// 直接调用
getName(); //小小,直接调用传统函数,其this是指向window的
getName1(); //小小,此时箭头函数声明所在的作用域是全局的window

// 使用call调用,call可以改变函数内部this的值
getName.call(school); //dada
getName1.call(school); //小小,结果没有改变,因为此时箭头函数声明所在的作用域还是全局的window

// 2、不能作为构造实例化对象
let Persion = (name,age) => {
    
    
	this.name = name;
	this.age = age;
 }
 let me = new Persion("訾博",24);
console.log(me);// 报错:Uncaught TypeError: Persion is not a constructor

// 3、不能使用 arguments 变量
let fn = () => console.log(arguments);
fn(1,2,3);// 报错:Uncaught ReferenceError: arguments is not defined

// 4.如果形参只有一个,则小括号可以省略
let add = n => {
    
    
    return n + n;
}

// 5.函数体如果只有一条语句,则花括号可以省略,且return也必须省略,该条语句的执行结果就是函数的返回值;
let pow = (n) => n*n;

案例一:点击 div 2s后颜色变成粉色

传统写法有问题:

<body>
	<div id="ad"></div>
    <script>
    // 获取元素
    let ad = document.getElementById('ad');
    // 绑定事件
    ad.addEventListener("click", function(){
      
      
        // 传统写法
        // 定时器:参数1:回调函数;参数2:时间;
        setTimeout(function(){
      
       
            console.log(this); //window,因为this引用的是把函数当成方法调用的上下文对象,setTimeout是JS自身的方法,所以其上下文对象是window
            this.style.background = 'pink';
        },2000);
        // 报错Cannot set property 'background' of undefined
    });   
    </script>
</body>

总结:在 setInterval 和 setTimeout 中传入函数时,函数中的 this 会指向 window 对象

传统解决问题的写法:

<script>
    // 获取元素
    let ad = document.getElementById('ad');
    // 绑定事件
    ad.addEventListener("click", function(){
      
      
        // 传统写法
        // 外部保存 this 的值
        let _this = this;
        // 定时器:参数1:回调函数;参数2:时间;
        setTimeout(function(){
      
       
            console.log(this);
        	_this.style.background = 'pink';//_this在当前作用域中找不到就会往外层找
        },2000);
        // 报错Cannot set property 'background' of undefined
    });
</script>

箭头函数解决问题的写法:

<script>
    // 获取元素
    let ad = document.getElementById('ad');
    // 绑定事件:这也是错误写法,这里的this还是window
    // ad.addEventListener("click", () => {
      
      
    //	setTimeout(() => this.style.background = 'pink',2000);
    // })
    // 绑定事件
    ad.addEventListener("click", function(){
      
      
        // ES6写法
        // 定时器:参数1:回调函数;参数2:时间;
        setTimeout(() => {
      
      
            this.style.background = 'pink' 
            //this是在外层的作用域里声明的,所以this指向事件源ad
        },2000);
    })
</script>

案例二:从数组中返回偶数的元素

//普通函数
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);

总结:

  • 箭头函数适合与 this 无关的回调。定时器,数组的方法回调
  • 箭头函数不适合与 this 有关的回调。DOM元素事件回调,,对象的方法

2.8 ES6中函数参数的默认值

ES6允许给函数的参数赋初始值;

作用:

  • 形参初始值赋值
  • 与解构赋值结合
<script>
    //ES6 允许给函数参数赋值初始值
    //1. 形参初始值,具有默认值的参数, 一般位置要靠后
    function add(a,b,c=10) {
      
      
    	return a + b + c;
    }
    let result = add(1,2); 
    console.log(result); // 13

    //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: 'atguigu.com', 
        username: 'root', 
        password: 'root', 
        port: 3306
    })
</script>

2.9 rest 参数

ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments;

参考文章:点击

// ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments;
// ES5获取实参的方式
function data(){
    
    
	console.log(arguments); //返回的是一个对象
}
data("大哥","二哥","三哥","四哥");

// ES6的rest参数...args,一个参数对象可对应多个实参,rest参数必须放在最后面
function data(...args){
    
    
	console.log(args); // 返回的是一个数组,就可以使用fliter some every map方法
}
data("大哥","二哥","三哥","四哥"); 

2.10 扩展运算符

... 扩展运算符能将数组转换为逗号分隔的参数序列

扩展运算符也是三个点(…)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列,对数组进行解包;

<script>
    // ... 扩展运算符能将数组转换为逗号分隔的参数序列
    const tfboys = ['易烊千玺', '王源', '王俊凯'];
    // => '易烊千玺','王源','王俊凯'

    function chunwan() {
      
      
        console.log(arguments);
    }
    chunwan(...tfboys); // 相当于chunwan('易烊千玺','王源','王俊凯')
</script>

应用

  • 数组的合并
  • 数组的克隆(是浅拷贝)
  • 将伪数组转为真正的数组
//1. 数组的合并 
const kuaizi = ['王太利','肖央']; 
const fenghuang = ['曾毅','玲花'];
// 传统的合并方式
// const zuixuanxiaopingguo = kuaizi.concat(fenghuang); 
// 利用扩展运算符
const zuixuanxiaopingguo = [...kuaizi, ...fenghuang]; 

//2. 数组的克隆
const sanzhihua = ['E','G','M'];
const sanyecao = [...sanzhihua]; //['E','G','M'] 

//3. 将伪数组转为真正的数组
const divs = document.querySelectorAll('div');  //假设html里面有3个div
const divArr = [...divs]; 
console.log(divArr); //[div,div,div]

2.11 Symbol

ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型

参考文章:https://blog.csdn.net/fesfsefgs/article/details/108354248

1. Symbol 特点:

  1. Symbol 的值是唯一的,用来解决命名冲突的问题;

  2. Symbol 值不能与其他数据进行运算

  3. Symbol 定义的对象属性不能使用 for…in 循环遍历 ,但是可以使用 Reflect.ownKeys 来获取对象的所有键名;

<script>
    // 创建Symbol
    let s = 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    
</script>

作用:symbol表示一个独一无二的值,可以给对象添加属性和方式

2. Symbol内置值

ES6 还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法。可以称这些方法为魔术方法,因为它们会在特定的场景下自动执行;

2.12 迭代器

迭代器是一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口(JS里面就是指对象里面的一个属性),就可以完成遍历操作;

特性:

  1. ES6 创造了一种新的遍历命令 for…of 循环

  2. Iterator 接口主要供 for…of 消费; 原生具备 iterator 接口的数据(可用 for of 遍历):

    • Array;
    • Arguments;
    • Set;
    • Map;
    • String;
    • TypedArray;
    • NodeList;

工作原理

  1. 创建一个指针对象,指向当前数据结构的起始位置;

  2. 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员;

  3. 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员;

  4. 每调用 next 方法返回一个包含 value 和 done(是否迭代完成的状态) 属性的对象;

注:需要自定义遍历数据的时候,要想到迭代器;

<script>
    // 声明一个数组
    const xiyou = ['唐僧', '孙悟空', '猪八戒', '沙僧'];

    // 使用 for...of 遍历数组
    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());

    // 重新初始化对象,指针也会重新回到最前面
    let iterator1 = xiyou[Symbol.iterator](); 
    console.log(iterator1.next());
</script>

迭代器实现自定义遍历数据:

<script>
    // 声明一个对象
    const banji = {
      
       
        name: "终极一班", 
        stus: ['xiaoming', 'xiaoning', 'xiaotian', 'knight'],
    	[Symbol.iterator]() {
      
      
            // 索引变量
            let index = 0;
            // 保存this
            let _this = this; 
            return {
      
      
                next: function() {
      
      
                	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 banji) {
      
       
        console.log(v);
        //xiaoming
        //xiaoning
        //xiaotian
        //knight
    }
</script>

2.13 生成器

生成器函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同,以前用的是春回调函数;

1. 基本用法

定义生成器函数:需要在函数名和 function 之间添加一个*

<script>
    // yield:函数代码的分隔符
    function* gen() {
      
      
    	console.log(111); 
        yield '一只没有耳朵';
        
        console.log(222); 
        yield '一只没有尾部'; 
        
        console.log(333); 
        yield ' 真 奇 怪 '; 
        
        console.log(444);
    }

    let iterator = gen(); //返回的iterator是个迭代器对象
    //iterator.next()会执行每个yield之前的内容并返回yield后面的value值和done的状态
    console.log(iterator.next()); 
    console.log(iterator.next()); 
    console.log(iterator.next()); 
    console.log(iterator.next());

    console.log("遍历:");
    //遍历
    for(let v of gen()){
      
       
        console.log(v);
    }
</script>

结果:

image-20220225083104701

2. 向生成器传入实参

后一个 next 方法中若传入实参,该实参将作为上一个 yield 语句的整体返回结果

function * gen(arg){
    
     
    console.log(arg); //AAA
    let one = yield 111; 
    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()); // 会执行yield 111;
// next()方法是可以传入参数的,传入的参数作为第一条(上一条)语句yield 111的返回结果

console.log(iterator.next("BBB")); // 会执行yield 222
console.log(iterator.next("CCC")); // 会执行yield 333; 
console.log(iterator.next("DDD")); // 继续往后走,未定义;

结果:
image-20220225083948112

3. 实例

实例1:

需求:1s后控制台输出111,再过2s后控制台输出222,再过3s后控制台输出333

function one(){
    
     
    setTimeout(()=>{
    
    
        console.log(111); 
        iterator.next(); //为了让输出222的任务继续执行
	},1000)
}

function two(){
    
     
    setTimeout(()=>{
    
    
    	console.log(222); 
        iterator.next(); 
	},1000)
}
function three(){
    
     
    setTimeout(()=>{
    
    
        console.log(333); 
        iterator.next();
	},1000)
}

function * gen(){
    
     
    yield one(); 
    yield two(); 
    yield three();
}

// 调用生成器函数
let iterator = gen(); 
iterator.next();

实例2:

需求:模拟获取: 用户数据,订单数据,商品数据,实际生活中有了用户才有订单,有了订单才有商品数据。

function getUsers(){
    
     
    setTimeout(()=>{
    
    
        let data = "用户数据";
        // 第二次调用next,传入参数,作为第一个的返回值
        iterator.next(data); // 这里将data传入,作为第一次yield的返回结果
    },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();

结果:

image-20220225085622061

2.14 Promise

Promise 是 ES6 引入的异步编程(文件操作 网络操作(ajax,request) 数据库操作)的新解决方案。语法上 Promise 是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果;

  1. Promise 构造函数: Promise (excutor) {}
  2. Promise.prototype.then 方法;
  3. Promise.prototype.catch 方法;

其做法就是:**将异步函数结果成功或失败的处理和操作提出来,以前是在回调函数中操作

每个promise对象都有两个属性:

  • PromiseState:保存Promise当前的状态
  • PromiseValue:保存Promise返回的值
// 实例化 Promise 对象
// Promise 对象三种状态:初始化、成功、失败
const p = new Promise(function(resolve,reject){
    
     
    // 封装一个异步操作
    setTimeout(function(){
    
    
    	// 成功
    	let data = "数据";
    	// 调用resolve,这个 Promise 对象 p 的状态就会变成成功
    	resolve(data);
    	// 失败
    	let err = "失败了!"; 
        reject(err);
	},1000);
});

// 就可以调用 Promise 对象的then方法
p.then(function(value){
    
     // 成功
	console.log(value);
}, function(reason){
    
     // 失败
	console.log(reason);
});

实例1:封装读文件的操作

写法一:一般写法

// 1、引入 fs 模块
const fs = require("fs");

// 2、调用方法,读取文件
fs.readFile("resources/text.txt",(err,data)=>{
    
    
    // 如果失败则抛出错误
    if(err) throw err;
    // 如果没有出错,则输出内容
    console.log(data.toString());
});

写法二:利用Promise

// 使用Promise封装
const p = new Promise(function(resolve,data){
    
     
    fs.readFile("resources/text.txt",(err,data)=>{
    
    
        // 判断如果失败
        if(err) reject(err);
        // 如果成功
        resolve(data);
    });
});

p.then(function(value){
    
      //成功
    console.log(value.toString());
},function(reason){
    
     
    console.log(reason); // 读取失败
})

实例2:封装Ajax请求

写法一:原生请求

// 请求地址:https://api.apiopen.top/getJoke
// 原生请求
// 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){
    
    
            // 成功
            console.log(xhr.response);
        } else{
    
    
            // 失败
            console.error(xhr.status);
        }
    }
}

写法二:利用Promise

// 请 求 地 址 :https://api.apiopen.top/getJoke 
const p = new Promise(function(resolve,reason){
    
    
    // 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{
    
    
                // 失败
                reason(xhr.status);
            }
        }
    }
});

p.then(function(value){
    
     
    console.log(value.toString());
},function(reason){
    
     
    console.log(reason); // 读取失败
})

2. Promise.prototype.then

要点:

  • 调用 then 方法,then 方法的返回结果是 promise 对象,所以可以链式调用;
  • Promise 对象的状态由回调函数的结果决定:
    • 如果回调函数中返回的结果是非 promise 类型的数据,则状态为成功返回值为对象的成功值
    • 如果返回的是 Promise 类型的数据,则该 Promise 对象的状态决定上面 Promise 对象 p 的状态;
    • 如果是抛出错误,则Promsie对象的状态为 rejected,PromiseValue就为抛出来的那个错误的值。
// 创建 Promise 对象
const p = new Promise((resolve,reject) => {
    
     
    setTimeout(() => {
    
    
        resolve("用户数据");
    },1000);
});

const result = p.then(value => {
    
    
    console.log(value);
    // 1、如果回调函数中返回的结果是非promise类型的数据,则状态为成功,返回值为对象的成功值
    // return 123;
    
    // 2、返回的是promise类型的数据,此Promise对象的状态决定上面Promise对象p的状态
    // return new Promise((resolve,reject)=>{
    
    
    //	resolve("ok"); // resolved
    //	reject("error"); // rejected
    // });
    
    // 3、抛出错误
    // throw new Error("失败啦!");
},reason => {
    
    
    console.error(reason);
})

// 链式调用
// then里面两个函数参数,可以只写一个
p.then(value=>{
    
    },reason=>{
    
    }).then(value=>{
    
    },reason=>{
    
    });

console.log(result); //是个Promise对象

在回调函数中什么也不返回的结果:

image-20220225092454502

3. 语法糖

image-20220225094231323

2.15 Set

ES6 提供了新的数据结构 Set(集合)。它类似于数组,但成员的值都是唯一的,集合实现了 iterator(迭代器)接口,所以可以使用 扩展运算符 和 **for…of…**进行遍历,

1. Set 的属性和方法

  1. new Set(接收一个可迭代数组),自动去重

  2. size:返回集合的元素个数;注意不是用 length!!!

  3. add:增加一个新元素,返回当前集合;

  4. delete:删除元素,返回 boolean 值;

  5. has:检测集合中是否包含某个元素,返回 boolean 值;

  6. clear:清空集合,返回 undefined;

// 创建Set集合
let s = new Set(); console.log(s,typeof s);
let s1 = new Set(["大哥","二哥","三哥","四哥","三哥"]);
console.log(s1); // 自动去重

// 1. size 返回集合的元素个数;
console.log(s1.size);

// 2. add 增加一个新元素,返回当前集合;
s1.add("大姐"); 
console.log(s1);

// 3. delete 删除元素,返回 boolean 值; 
let result = s1.delete("三哥"); 
console.log(result);
console.log(s1);

// 4. has 检测集合中是否包含某个元素,返回 boolean 值;
let r1 = s1.has("二姐"); 
console.log(r1);

// 5. clear 清空集合,返回 undefined; 
s1.clear();
console.log(s1);

结果:
image-20220225094807305

2. Set实践

let arr = [1,2,3,4,5,4,3,2,1];
// 1.数组去重
let res1 = [...new Set(arr)]; 
console.log(res1);

// 2.交集
let arr2 = [3,4,5,6,5,4,3];
let res2 = [...new Set(arr)].filter(item => new Set(arr2).has(item));
console.log(res2);

// 3.并集
// ... 为扩展运算符,将数组转化为逗号分隔的序列
let union = [...new Set([...arr,...arr2])]; 
console.log(union);

// 4.差集:比如集合1和集合2求差集,就是1里面有的,2里面没的,要看谁是谁的差集,是交集的逆运算
let result1 = [...new Set(arr)].filter(item =>!(new Set(arr2).has(item)));
console.log(result1);

image-20220225095532014

2.16 Map

ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合。但是**“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键**。Map 也实现了iterator 接口,所以可以使用**『扩展运算符』『for…of…』**进行遍历;

Map 的属性和方法:

  1. size:返回 Map 的元素个数;

  2. set: 增加一个新元素,返回当前 Map;

  3. get:返回键名对象的键值;

  4. has:检测 Map 中是否包含某个元素,返回 boolean 值;

  5. clear:清空集合,返回 undefined;

2.17 Class 类

ES6 提供了更接近传统语言(Java,C++)的写法,引入了 Class(类)这个概念,作为对象的模板。通过 class 关键字,可以定义类。基本上,ES6 的 class 可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已

要点:

  1. class 声明类;

  2. constructor 定义构造函数初始化;

  3. extends 继承父类;

  4. super 调用父级构造方法;

  5. static 定义静态方法和属性;

  6. 父类方法可以重写;

// ES5写法
function Phone(brand,price){
    
    
    this.brand = brand;
    this.price = price;
}
// 添加方法
Phone.prototype.call = function(){
    
    
    console.log("我可以打电话!");
}
// 实例化对象
let HuaWei = new Phone("华为",5999);
HuaWei.call();
console.log(HuaWei);

// ES6写法
class shouji{
    
    
    // 构造方法,名字是固定的
    constructor(brand,price) {
    
     
        this.brand = brand; 
        this.price = price;
    }

    // 打电话,方法必须使用该方式写,不能用写其他函数的方法写
    call(){
    
    
        console.log("我可以打电话!");
    }
}

let HuaWeiplus = new shouji("华为",5999); 
HuaWeiplus.call();
console.log(HuaWeiplus); //输出一个shouji的实例对象

1. Class 中的静态成员

要点:

  • ES5 中实例对象和函数对象的属性是不相通的,实例对象跟构造函数的原型对象是相通的。函数对象的属性属于函数对象,不属于实例对象。
  • ES6 中类中加了 static 的属性是静态属性,静态属性属于类而不属于实例对象
// class静态成员
// ES5写法
function Phone(){
    
    }
Phone.name = "手机"; //name是静态成员
Phone.change = function(){
    
    
    console.log("我可以改变世界!");
}
let nokia = new Phone();
console.log(nokia.name); // undefined
nokia.change(); //报错:Uncaught TypeError: nokia.change is not a function
// 原因:实例对象(nokia)和函数对象(phone)的属性是不相通的,实例对象跟构造函数(phone)原型对象是相通的。函数对象的属性属于函数对象,不属于实例对象。
Phone.prototype.color = "黑色";
console.log(nokia.color); // 黑色

// ES6写法
class Phone{
    
    
    // 静态属性,属于类而不属于实例对象
    static name = "手机";  
	static change(){
    
    
        console.log("我可以改变世界!");
    }
}
let nokia = new Phone(); 
console.log(nokia.name); //undefined

2. 构造函数实现继承

// ES5构造函数继承
// 手机
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的指向
    this.color = color; 
    this.size = size;
}

// 设置子级构造函数的原型
SmartPhone.prototype = new Phone; 
SmartPhone.prototype.constructor = SmartPhone;

// 声明子类的方法
SmartPhone.prototype.photo = function(){
    
     
    console.log("我可以拍照!");
}

SmartPhone.prototype.game = function(){
    
     
    console.log("我可以玩游戏!");
}

const chuizi = new SmartPhone("锤子",2499,"黑色","5.5inch"); 
console.log(chuizi);
chuizi.call(); 
chuizi.photo(); 
chuizi.game();

// ES6 class类继承
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("我可以拍照!");
    }
    game(){
    
    
        console.log("我可以玩游戏!");
    }
}

const chuizi = new SmartPhone("小米",1999,"黑色","5.15inch"); 
console.log(chuizi);
chuizi.call(); 
chuizi.photo(); 
chuizi.game();

ES5中的结果:
image-20220225103929548

ES6中的结果:
image-20220225103950669

3. 子类对父类方法的重写

在子类声明一个跟父类同名的方法

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.size = size;
    }
    
    photo(){
    
    
        console.log("我可以拍照!");
    }
    game(){
    
    
        console.log("我可以玩游戏!");
    }
    
    // 子类对父类方法重写:直接写,直接覆盖
    // 注意:子类无法调用父类同名方法,super也不行
    call(){
    
    
        console.log("我可以进行视频通话!");
    }
}

const chuizi = new SmartPhone("小米",1999,"黑色","5.15inch");
console.log(chuizi);
chuizi.call(); //调用的是子类的方法
chuizi.photo(); 
chuizi.game();

结果:

image-20220225104510518

4. class 中 getter 和 setter

// class中的getter和setter设置 
class Phone{
    
    
    get price(){
    
    
        console.log("价格属性被读取了!");
        // 返回值
        return 123;
    }
    set price(newVal){
    
     
        console.log("价格属性被修改了!");
    }
}

// 实例化对象
let s = new Phone(); 
console.log(s.price); //"价格属性被读取了!"  123;
s.price = 'free'  //"价格属性被修改了!"

2.18 数值扩展

  • Number.EPSILON

Number.EPSILON 是 JavaScript 表示的最小精度;

EPSILON 属性的值接近于 2.2204460492503130808472633361816E-16;

应用:主要用在浮点数的运算上

  • 二进制和八进制:

ES6 提供了二进制和八进制数值的新的写法,分别用前缀 0b 和 0o 表示;

  • Number.isFinite() Number.isNaN()

Number.isFinite() 用来检查一个数值是否为有限的;

Number.isNaN() 用来检查一个值是否为 NaN;

  • Number.parseInt() Number.parseFloat()

ES6 将全局方法 parseInt 和 parseFloat,移植到 Number 对象上面,使用不变;

  • Math.trunc

用于去除一个数的小数部分,返回整数部分;

  • Number.isInteger

Number.isInteger() 用来判断一个数值是否为整数;

// 0. Number.EPSILON 
function equal(a, b){
    
    
    return Math.abs(a-b) < Number.EPSILON;
} 
// 箭头函数简化写法
equal = (a, b) => Math.abs(a-b) < Number.EPSILON;
console.log(0.1 + 0.2 === 0.3);// false
console.log(equal(0.1 + 0.2, 0.3)); // true

// 1. 二进制和八进制
let b = 0b1010;
let o = 0o777; 
let d = 100; 
let x = 0xff; 
console.log(x);

// 2. Number.isFinite	检测一个数值是否为有限数
console.log("2、Number.isFinite	检测一个数值是否为有限数"); 
console.log(Number.isFinite(100)); 
console.log(Number.isFinite(100/0)); 
console.log(Number.isFinite(Infinity));

// 3. Number.isNaN 检 测 一 个 数 值 是 否 为 NaN 
console.log("3. Number.isNaN 检测一个数值是否为 NaN"); console.log(Number.isNaN(123));

// 4. Number.parseInt Number.parseFloat字符串转整数
console.log(Number.parseInt('5211314love'));  //5211314
console.log(Number.parseFloat('3.1415926神奇'));  //3.1415926

// 5. Number.isInteger 判断一个数是否为整数
console.log(Number.isInteger(5)); 
console.log(Number.isInteger(2.5));

// 6. Math.trunc 将数字的小数部分抹掉
console.log(Math.trunc(3.5)); //3

// 7. Math.sign 判断一个数到底为正数 负数 还是零
console.log(Math.sign(100)); //1
console.log(Math.sign(0));  //0
console.log(Math.sign(-20000)); //-1

2.19 对象方法的扩展

ES6 新增了一些 Object 对象的方法:

  1. Object.is 用来比较两个值是否严格相等,与『===』行为基本一致,除了(+0 与 NaN);

  2. Object.assign用于对象的合并,将源对象的所有可枚举属性,复制到目标对象;

  3. proto、Object.setPrototypeOf、 Object.setPrototypeOf 可以直接设置原型对象

// 1. Object.is 比较两个值是否严格相等
console.log(Object.is(120,120)); // ===
// 注意下面的区别
console.log(Object.is(NaN,NaN)); //true
console.log(NaN === NaN); //false
// NaN与任何数值做===比较都是false,跟他自己也如此!

// 2. Object.assign 对象的合并
const config1 = {
    
    
    host : "localhost", 
    port : 3306,
    name : "root",
    pass : "root",
    test : "test" //唯一存在的
}

const config2 = {
    
    
    host : "http://zibo.com", 
    port : 300300600,
    name : "root4444", 
    pass : "root4444", 
    test2 : "test2"
}
// 如果前边有后边没有会添加,如果前后都有,后面的会覆盖前面的,后面有的前面没有的不会添加
console.log(Object.assign(config1,config2));

// 3. proto 、setPrototypeOf、 getPrototypeOf 可以直接设置对象的原型;
const school = {
    
     
    name : "尚硅谷"
}
const cities = {
    
    
    xiaoqu : ['北京','上海','深圳']
}
// 并不建议这么做
Object.setPrototypeOf(school,cities);
console.log(Object.getPrototypeOf(school)); 
console.log(school);

结果:
image-20220225110539280

2.20 模块化

模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来;

这里讲一下 ES6 import 和 export 的知识点

1. ES6模块数据暴露语法(export)汇总

m.js(逐个导出模块):

// 分别暴露(导出)
export let school = "尚硅谷";
export function teach(){
    
     
    console.log("我们可以教你开发技术!");
}

n.js(统一导出模块):

// 统一暴露(导出)
let school = "尚硅谷";
function findJob(){
    
          
    console.log("我们可以帮你找到好工作!");
}
export {
    
    school,findJob}

o.js(默认导出模块):

// 默认暴露(导出)
export default{
    
     
    school : "尚硅谷",
    change : function(){
    
     
        console.log("我们可以帮你改变人生!");
    }
}

index.html(引入和使用模块):
img

结果:
image-20220225111349980

2. ES6导入模块语法(import)汇总

<script type="module">
    // 1.通用方式
    // 引入m.js模块内容
    import * as m from "./js/m.js"; 
    console.log(m); 
    console.log(m.school); 
    m.teach();
    
    // 引入n.js模块内容
    import * as n from "./js/n.js";
    console.log(n); 
    console.log(n.school); 
    n.findJob();
    
    // 引入o.js模块内容
    import * as o from "./js/o.js"; 
    console.log(o);
    // 注意这里调用方法的时候需要加上default
    console.log(o.default.school); 
    o.default.change();
    
    // 2.解构赋值形式
    import {
      
      school,teach} from "./js/m.js";
    // 重名的可以使用别名
    import {
      
      school as xuexiao,findJob} from "./js/n.js";
    // 导入默认导出的模块,必须使用别名
    import {
      
      default as one} from "./js/o.js";
    // 直接可以使用
    console.log(school); 
    teach();
    console.log(xuexiao);
    console.log(one); 
    console.log(one.school); 
    one.change();
    
    // 3.简便形式,只支持默认导出
    import oh from "./js/o.js"; 
    console.log(oh); 
    console.log(oh.school); 
    oh.change();
</script>

image-20220225112022281

浏览器使用ES6模块化的方式是将代码整合到另一个文件中,然后用 script 标签引入,但需要指定 type = "module":

其他具体要点见我的另两篇文章 前端工程化Webpack 究竟是什么?如何理解Webpack 中关于对模块化的讲解。

2.21 Babel对ES6模块化代码转换

1. babel 是什么

Babel 是一个 JavaScript 编译器,能够将新的ES规范语法转换成ES5的语法;因为不是所有的浏览器都支持最新的ES规范,所以一般项目中都需要使用Babel进行转换;

具体的使用方法见 Webpack 究竟是什么?如何理解Webpack

2.22 ES6模块化引入NPM包

三、ES7 新特性

新特性总体概况

1、Array.prototype.includes

  • 判断数组中是否包含某元素,语法:arr.includes(元素值);

2、指数操作符

  • 在 ES7 中引入指数运算符「**」,用来实现幂运算,功能与 Math.pow 结果相同;例如:2的10次方:2**10;

四、ES8 新特性

4.1 新特性总体概况

1、async 和 await

  • 简化异步函数的写法;

2、对象方法扩展

4.2 async 和 await

async 和 await 两种语法结合可以让异步代码看起来像同步代码一样,简化异步函数的写法;

1. async 函数要点

  1. async 函数的返回值为 promise 对象;

  2. promise 对象的结果由 async 函数执行的返回值决定:

    • 只要返回的值不是 promise 类型的对象,哪怕是没有返回的值,都是一个成功的 Promise 对象
    • 返回的结果是一个 Promise 对象,Promise 对象是成功的,那 async 函数返回的结果也是成功的。成功的值就是Promise对象返回的结果。

2. await 表达式要点

  1. await 必须写在 async 函数中;

  2. await 右侧的表达式一般为 promise 对象;

  3. await 返回的是 promise 成功的值

  4. await 的 promise 失败了, 就会抛出异常, 需要通过 try…catch 捕获处理

// 创建Prmise对象
const p = new Promise((resolve,reject)=>{
    
     
    resolve("成功啦!");
})
async function fn(){
    
    
    // await 返回的是 promise 成功的值
    let result = await p; 
    console.log(result); // 成功啦!
}
fn();

3. async await 读取文件案例

// 导入模块
const fs = require("fs");

// 读取
function readText() {
    
    
    return new Promise((resolve, reject) => {
    
     
        fs.readFile("../resources/text.txt", (err, data) => {
    
    
            //如果失败
            if (err) reject(err);
            //如果成功
            resolve(data);
        })
    })
}

function readText1() {
    
    
    return new Promise((resolve, reject) => {
    
     
        fs.readFile("../resources/test1.txt", (err, data) => {
    
    
            //如果失败
            if (err) reject(err);
            //如果成功
            resolve(data);
        })
    })
}

function readText2() {
    
    
    return new Promise((resolve, reject) => {
    
     
        fs.readFile("../resources/test2.txt", (err, data) => {
    
    
            //如果失败
            if (err) reject(err);
            //如果成功
            resolve(data);
        })
    })
}

//声明一个 async 函数
async function main(){
    
    
    //获取文本1内容
    let t0 = await readText();
    //获取文本2内容
    let t1 = await readText1();
    //获取文本3有感
    let t2 = await readText2();

    console.log(t0.toString()); 
    console.log(t1.toString()); 
    console.log(t2.toString());
}

4. async await 结合发送ajax请求

// async 和 await 结合发送ajax请求
function sendAjax(url){
    
    
    return new Promise((resolve,reject)=>{
    
    
        // 1、创建对象
        const x = new XMLHttpRequest();

        // 2、初始化
        x.open("GET",url);

        // 3、发送
        x.send();

        // 4、事件绑定
        x.onreadystatechange = function(){
    
     
            if(x.readyState == 4){
    
    
                if(x.status>=200 && x.status<300){
    
    
                    // 成功
                    resolve(x.response);
                }else{
    
    
                    // 失败
                    reject(x.status);
                }
            }
        }
    });
}

//使用 async 和 await 
async function main(){
    
    
    //发送Ajax请求
    let result = await sendAjax("https://api.apiopen.top/getJoke"); 				console.log(result);
}
main();

4.3 对象方法扩展

ES8 中扩展的对象方法有:Object.valuesObject.valuesObject.entriesObject.getOwnPropertyDescriptors

  1. Object.keys():获取对象所有的

  2. Object.values():获取对象所有的值,返回一个给定对象的所有可枚举属性值的数组

  3. Object.entries():返回给定对象自身可遍历属性 [key,value] 的数组

  4. Object.getOwnPropertyDescriptors():返回指定对象所有自身属性的描述对象

// 对象方法扩展
let school = {
    
     
    name : "訾博", 
    age : 24,
    sex : "男"
}

// 获取对象所有的键
console.log(Object.keys(school));
// 获取对象所有的值
console.log(Object.values(school));
// 获 取 对 象 的 entries 
console.log(Object.entries(school));

// 创建map
const map = new Map(Object.entries(school));
console.log(map); 
console.log(map.get("name"));

// 返回指定对象所有自身属性的描述对象
console.log(Object.getOwnPropertyDescriptors(school));
// 参考内容:
const obj = Object.create(null,{
    
     
    name : {
    
    
        // 设置值
        value : "訾博",
        // 属性特性
        writable : true, 
        configuration : true, 
        enumerable : true
    }
});

image-20220225142102079

五、ES9的新特性

5.1 新特性总体概况

1、Rest 参数与 spread 扩展运算符

2、正则扩展

5.2 扩展运算符和rest参数

Rest 参数和扩展运算符在 ES6 中已经引入,不过 ES6 中是只针对数组,在 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', 
    type: 'master'
});

//对象合并
const skillOne = {
    
     q: '天音波'} // ...skillOne	=>	q: '天音波'
const skillTwo = {
    
     w: '金钟罩'}
const skillThree = {
    
     e: '天雷破'}
const skillFour = {
    
     r: '猛龙摆尾', z: '胡说八道'}

const mangseng = {
    
    ...skillOne,...skillTwo,...skillThree,...skillFour};

console.log(mangseng)

结果:
image-20220225142747227

5.3 正则扩展

1. 命名捕获分组

ES9 允许命名捕获组使用符号『?』,这样获取捕获结果可读性更强;

// 需求:提取url和标签内文本
let str = '<a href="http://www.baidu.com">訾博</a>';

// 之前的写法
const reg = /<a href="(.*)">(.*)<\/a>/;
// 执行
const result = reg.exec(str); 
console.log(result);
// 结果是一个数组,第一个元素是所匹配的所有字符串
// 第二个元素是第一个(.*)匹配到的字符串
// 第三个元素是第二个(.*)匹配到的字符串
// 我们将此称之为捕获
console.log(result[1]); 
console.log(result[2]);

// 命名捕获分组
const reg1 = /<a href="(?<url>.*)">(?<text>.*)<\/a>/;
const result1 = reg1.exec(str);
console.log(result1);
// 这里的结果多了一个groups
// groups:
// text:"訾博"
// url:"http://www.baidu.com" 
console.log(result1.groups.url); 
console.log(result1.groups.text);

image-20220225143212175

2. 反向断言

ES9 支持反向断言,通过对匹配结果前面的内容进行判断,对匹配进行筛选;

// 需求:我们只想匹配到555
// 字符串
let str = "JS5201314你知道么555啦啦啦";

// 正向断言
const reg = /\d+(?=啦)/; // 前面是数字后面是啦
const result = reg.exec(str); 
console.log(result);
// 反向断言
const reg1 = /(?<=么)\d+/; //后面是数字前面是么
const result1 = reg.exec(str); 
console.log(result1);

image-20220225143644075

3. dotAll 模式

正则表达式中的点.匹配除回车外的任何单字符,标记『s』改变这种行为,允许行终止符出现;

// 需求:我们想要将url其中的电影名称和对应上映时间提取出来,存到对象中
// dot就是. 元字符,表示除换行符之外的任意单个字符
let str = `
<ul>
    <li>
        <a>肖生克的救赎</a>
        <p>上映日期: 1994-09-10</p>
    </li>
    <li>
        <a>阿甘正传</a>
        <p>上映日期: 1994-07-06</p>
    </li>
</ul>`;

// 之前的写法
const reg = /<li>\s+<a>(.*?)<\/a>\s+<p>(.*?)<\/p>/;

// dotAll 模式
const reg = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/gs;
const result = reg.exec(str);
console.log(result); 

let result;
let data = [];
while(result = reg.exec(str)){
    
     
    console.log(result); 
    data.push({
    
    title:result[1],time:result[2]});
}
console.log(data);

结果:
image-20220225144330301

六、ES10的新特性

6.1 新特性总体概况

对象扩展方法

1、Object.fromEntries

  • 将二维数组或者map转换成对象;

2、trimStart 和 trimEnd

  • 去除字符串前后的空白字符;

3、Array.prototype.flat与 flatMap

  • 将多维数组降维;

4、Symbol.prototype.description

  • 获取Symbol的字符串描述;

6.2 Object.fromEntries

将二维数组或者 map 转换成对象;之前学的Object.entries是将对象转换成二维数组;

const result = Object.fromEntries([ 
    ["name","小小"],
	["age",24],
]);

console.log(result);

const m = new Map(); 
m.set("name","小小");
m.set("age",24);
const result1 = Object.fromEntries(m); 
console.log(result1);

结果:

image-20220225145051699

6.3 Array.prototype.flat与 flatMap

将多维数组转换成低维数组;

// flat
// 将多维数组转换成低维数组
// 1.将二维数组转换成一维数组
const arr = [1,2,3,[4,5],6,7];
console.log(arr.flat());
// 2.将三维数组转换成二维数组
const arr2 = [1,2,3,[4,5,[6,7]],8,9];
console.log(arr2.flat());
// 3.将三维数组转换成一维数组,数字2表示深度,没有传数字默认降低一维
console.log(arr2.flat(2));

// flatMap,若Map返回的是多维数组,则可降维
const arr3 = [1,2,3,4,5];
const result0 = arr3.map(item => item * 10); 
console.log(result0);
const result = arr3.map(item => [item * 10]); 
console.log(result);
const result1 = arr3.flatMap(item => [item * 10]); 
console.log(result1);

image-20220225145530753

6.4 Symbol.prototype.description

获取Symbol的描述字符串;

let s = Symbol("小小"); 
console.log(s.description) //小小

七、ES11的新特性

7.1 新特性总体概况

1、类的私有属性

  • 私有属性外部不可访问直接;

2、Promise.allSettled

  • 获取多个promise执行的结果集;

3、String.prototype.matchAll

  • 用来得到正则批量匹配的结果;

4、可选链操作符

  • 简化对象存在的判断逻辑

5、动态 import 导入

  • 动态导入模块,什么时候使用什么时候导入;

6、BigInt

7、绝对全局对象globalThis

  • 始终指向全局对象window;

7.2 类的私有属性

// 类的私有属性
class Person{
    
    
    // 公有属性
    name;
    // 私有属性
    #age;
    #weight;
    // 构造方法
    constructor(name, age, weight){
    
     
        this.name = name;
        this.#age = age; 
        this.#weight = weight;
    }
	intro(){
    
    
        console.log(this.name); 
        console.log(this.#age); 
        console.log(this.#weight);
    }
}

// 实例化
const girl = new Person("小兰",18,"90kg"); 
console.log(girl);
// 公有属性的访问
console.log(girl.name);
// 私有属性的访问
console.log(girl.age); // 报错:Private field '#age' must be declared in an enclosing class

girl.intro(); //可以访问

7.3 Promise.allSettled

获取多个promise执行的结果集;返回的结果 PromiseStatus 永远是成功的状态。PromiseValue是每个对象值合起来的数组

const p1 = new Promise((resolve,reject)=>{
    
     
    setTimeout(()=>{
    
    
        resolve("商品数据-1");
    },1000);
});

const p2 = new Promise((resolve,reject)=>{
    
     
    setTimeout(()=>{
    
    
        reject("失败啦");
    },1000);
});

// 调用Promise.allSettled方法
const result = Promise.allSettled([p1,p2]); 
console.log(result);
const result1 = Promise.all([p1,p2]); // 注意区别
console.log(result1);

Promise.all 是要所有的 Promise 对象都成功才返回成功,不然就是失败的Promise对象。而Promise.allSettled的结果永远是成功的状态。
image-20220225151847111

7.4 String.prototype.matchAll

// String.prototype.matchAll
// 用来得到正则批量匹配的结果
let str = `
    <ul>
        <li>
            <a>肖生克的救赎</a>
            <p>上映日期: 1994-09-10</p>
        </li>
        <li>
            <a>阿甘正传</a>
            <p>上映日期: 1994-07-06</p>
        </li>
    </ul>`;
// 正则
const reg = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/sg; 
const result = str.matchAll(reg);
// 返回的是可迭代对象,可用扩展运算符展开
console.log(...result);

// 也可使用for...of...遍历
for(let v of result){
    
     
    console.log(v);
}

image-20220225152156377

7.5 可选链操作符

如果存在则往下走,省略对对象是否传入的层层判断;

// 可选链操作符 ?.
function main(config){
    
    
    // 传统写法
    const dbHost = config && config.db && config.db.host;
    // 可选链操作符写法
    const dbHost = config?.db?.host; //前面一项有就往下走,没有返回undefined 不会报错
    console.log(dbHost);
}
main({
    
    
    db:{
    
    
        host:"192.168.1.100",
        username:"root"
    },
    cache:{
    
    
        host:"192.168.1.200",
        username:"admin"
    }
});

7.6 动态 import 导入(按需加载)

以前的 import 是一股脑把所有需要的模块全部导进来,就不能实现懒加载,效率也较低。

使用 import 动态导入后返回的是一个 Promise 对象。

// index.html
<body>
    <button id="btn">点击</button>
    <script src="app.js" type="module"></script>
</body>
//hello.js
export function hello(){
    
     
    alert('Hello');
}
//app.js
// import * as m1 from "./hello.js"; // 传统静态导入
//获取元素
const btn = document.getElementById('btn');

btn.onclick = function(){
    
     
    import('./hello.js').then(module => {
    
     //module就是导入的模块中暴露的对象
        module.hello();
    });
}

7.7 Bigint

注意:bigint类型不能直接跟普通的 int 类型做运算

// 大整型
let n = 100n; 
console.log(n,typeof(n));

// 函数:普通整型转大整型
let m = 123; 
console.log(BigInt(m));  //123n

// 大数值运算
let max = Number.MAX_SAFE_INTEGER;  //最大安全整数
console.log(max); 
console.log(max+1); 
console.log(max+2);

console.log(BigInt(max)); 
console.log(BigInt(max)+BigInt(1)); 
console.log(BigInt(max)+BigInt(2));

结果:

image-20220225153324903

7.8 绝对全局对象globalThis

无论执行环境是什么,始终指向全局对象

猜你喜欢

转载自blog.csdn.net/weixin_45950819/article/details/123134455