ES6

ES6-ES11 学习笔记

学习笔记的来源:在B站观看尚硅谷的ES6视频教程并做相应的笔记,仅供参考

一、概述

1、什么是 ECMA

ECMA(European Computer Manufacturers Association)中文名称为欧洲计算机制造商协会,这个组织的目标是评估、开发和认可电信和计算机标准。1994 年后该组织改名为 Ecma 国际

2、什么是 ECMAScript

ECMAScript 是由 Ecma 国际通过 ECMA-262 标准化脚本 的程序设计语言;

百度百科:https://baike.baidu.com/history/ECMAScript/1889420/144946978

3、什么是 ECMA-262

Ecma 国际制定了许多标准,而 ECMA-262 只是其中的一个,所有标准列表查看:

http://www.ecma-international.org/publications/standards/Standard.htm

4、ECMA-262 历史

ECMA-262(ECMAScript)历史版本查看网址:
http://www.ecma-international.org/publications/standards/Ecma-262-arch.htm

1644482820752

注:从 ES6 开始,每年发布一个版本,版本号比年份最后一位大 1;

5、谁在维护 ECMA-262

TC39(Technical Committee 39)是推进 ECMAScript 发展的委员会。其会员都是公司(其中主要是浏览器厂商,有苹果、谷歌、微软、因特尔等)。TC39 定期召开会议,会议由会员公司的代表与特邀专家出席;

6、为什么要学习 ES6

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

7、ES6 兼容性

查看网址:http://kangax.github.io/compat-table/es6

二、ES6 新特性

0、功能概述

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包;

1、let 关键字

特性:

let 关键字用来声明变量,使用 let 声明的变量有几个特点:

  1. 不允许重复声明
  2. 块儿级作用域(局部变量)
  3. 不存在变量提升
  4. 不影响作用域链

let创建变量代码示例:

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

代码实现:

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

运行结果:

1644483255220

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

代码实现:

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

运行结果:

1644483336140

不存在变量提升:

什么是变量提升
就是在变量创建之前使用(比如输出:输出的是默认值),let不存在,var存在;
代码实现:

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

运行结果:

1644483388149

不影响作用域链:

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

代码实现:

// 4. 不影响作用域链;
// 什么是作用域链:很简单,就是代码块内有代码块,跟常规编程语言一样,上级代码块中的局部变量下级可用
{
	let p = "大哥";
	function fn(){
		console.log(p); // 这里是可以使用的
	}
	fn();
}

运行结果:

1644483486198

全部演示代码:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>let</title>
</head>

<body>
    let
    <script>
        // let 关键字使用示例
        let a; // 单个声明
        let b, c, d; // 批量声明
        let e = 100; // 单个声明并赋值
        let f = 521, g = 'iloveyou', h = []; // 批量声明并赋值
// let 关键字特性
// 1. 不允许重复声明;
// let dog = "狗";
// let dog = "狗";
// 报错:Uncaught SyntaxError: Identifier 'dog' has already been declared
// 2. 块儿级作用域(局部变量);
// {
// let cat = "猫";
// console.log(cat);
// }
// console.log(cat);
// 报错:Uncaught ReferenceError: cat is not defined
// 3. 不存在变量提升;
// 什么是变量提升:就是在变量创建之前使用(比如输出:输出的是默认值),let不存在,var存在;
// console.log(people1); // 可输出默认值
// console.log(people2); // 报错:Uncaught ReferenceError: people2 is not defined
// var people1 = "大哥"; // 存在变量提升
// let people2 = "二哥"; // 不存在变量提升
// 4. 不影响作用域链;
// 什么是作用域链:很简单,就是代码块内有代码块,跟常规编程语言一样,上级代码块中的局部变量下级可用
// {
// let p = "大哥";
// function fn(){
// console.log(p); // 这里是可以使用的
// }
// fn();
// }
    </script>
</body>

</html>

应用场景:
以后声明变量使用 let 就对了;

let案例:点击div更改颜色

代码实现:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>let案例:点击div更改颜色</title>
    <link crossorigin="anonymous" href="https://cdn.bootcss.com/twitter-
bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    <style>
        .item {
            width: 100px;
            height: 50px;
            border: solid 1px rgb(42, 156, 156);
            float: left;
            margin-right: 10px;
        }
    </style>
</head>

<body>
    <div class="container">
        <h2 class="page-header">let案例:点击div更改颜色</h2>
        <div class="item"></div>
        <div class="item"></div>
        <div class="item"></div>
    </div>
    <script>
        // 获取div元素对象
        let items = document.getElementsByClassName('item');
        // 遍历并绑定事件
        for (let i = 0; i < items.length; i++) {
            items[i].onclick = function () {
                // 修改当前元素的背景颜色
                // this.style.background = 'pink'; // 写法一:常规写法一般无异常
                items[i].style.background = 'pink'; // 写法二
                // 写法二:需要注意的是for循环内的i必须使用let声明
                // 如果使用var就会报错,因为var是全局变量,
                // 经过循环之后i的值会变成3,items[i]就会下标越界
                // let是局部变量
                // 我们要明白的是当我们点击的时候,这个i是哪个值
                // 使用var相当于是:
                // { var i = 0; }
                // { var i = 1; }
                // { var i = 2; }
                // { var i = 3; }
                // 下面的声明会将上面的覆盖掉,所以点击事件每次找到的都是3
                // 而使用let相当于是:
                // { let i = 0; }
                // { let i = 1; }
                // { let i = 2; }
                // { let i = 3; }
                // 由于let声明的是局部变量,每一个保持着原来的值
                // 点击事件调用的时候拿到的是对应的i
            }
        }
    </script>
</body>

</html>

运行结果:

1644483789035

2、const 关键字

特性:

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

  1. 声明必须赋初始值;
  2. 标识符一般为大写(习惯);
  3. 不允许重复声明;
  4. 值不允许修改;
  5. 块儿级作用域(局部变量);

const创建变量代码示例:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>const</title>
</head>

<body>
    <script>
        // const声明常量
        const DOG = "旺财";
        console.log(DOG);
        
    </script>
</body>

</html>
声明必须赋初始值:

代码实现

// 1. 声明必须赋初始值;       
const CAT;

运行结果:

1644484011241

不允许重复声明:

代码实现:

// 3. 不允许重复声明;
const CAT = "喵喵";
const CAT = "喵喵";

运行结果:

1644484053176

值不允许修改:

注意:对数组元素的修改和对对象内部的修改是可以的(数组和对象存的是引用地址);
代码实现:

// 4. 值不允许修改;
const CAT = "喵喵";
CAT = "咪咪";

运行结果:

1644484124244

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

代码实现:

// 5. 块儿级作用域(局部变量);
{
const CAT = "喵喵";
console.log(CAT);
}
console.log(CAT);

运行结果:

1644484161896

全部演示代码:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>const</title>
</head>

<body>
    <script>
        // const声明常量
        const DOG = "旺财";
        console.log(DOG);
        // 1. 声明必须赋初始值;
        // const CAT;
        // 报错:Uncaught SyntaxError: Missing initializer in const declaration

        // 2. 标识符一般为大写(习惯);
        // const dog = "旺财"; // 小写也不错

        // 3. 不允许重复声明;
        // const CAT = "喵喵";
        // const CAT = "喵喵";
        // 报错:Uncaught SyntaxError: Identifier 'CAT' has already been declared

        // 4. 值不允许修改;
        // const CAT = "喵喵";
        // CAT = "咪咪";
        // 报错:Uncaught TypeError: Assignment to constant variable.

        // 5. 块儿级作用域(局部变量);
        // {
            // const CAT = "喵喵";
            // console.log(CAT);
        // }
        // console.log(CAT);
        // 报错:Uncaught ReferenceError: CAT is not defined
    </script>
</body>

</html>

应用场景:
声明对象类型使用 const,非对象类型声明选择 let;

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

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

代码演示及相关说明:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>解构赋值</title>
</head>

<body>
    <script>
        // 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(); // 此方法可以正常调用
    </script>
</body>

</html>

应用场景:
频繁使用对象方法、数组元素,就可以使用解构赋值形式;

4、模板字符串

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

  • 字符串中可以出现换行符;
  • 可以使用 ${xxx} 形式引用变量;

代码演示及相关说明:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title></title>
</head>

<body>
    <script>
        // 声明字符串的方法:单引号('')、双引号("")、反引号(``)
        // 声明
        let string = `我也一个字符串哦!`;
        console.log(string);
        // 特性
        // 1、字符串中可以出现换行符
        let str =`<ul>
                    <li>大哥</li>
                    <li>二哥</li>
                    <li>三哥</li>
                    <li>四哥</li>
                 </ul>`;
        console.log(str);
        // 2、可以使用 ${xxx} 形式引用变量
        let s = "大哥";
        let out = `${s}是我最大的榜样!`;
        console.log(out);
    </script>
</body>
</html>

应用场景:
当遇到字符串与变量拼接的情况使用模板字符串

5、简化对象和函数写法

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

代码示例及相关说明:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>简化对象写法</title>
</head>

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

6、箭头函数

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

箭头函数的注意点

  1. 如果形参只有一个,则小括号可以省略;
  2. 函数体如果只有一条语句,则花括号可以省略,函数的返回值为该条语句的执行结果;
  3. 箭头函数 this 指向声明时所在作用域下 this 的值
  4. 箭头函数不能作为构造函数实例化
  5. 不能使用 arguments;

特性

  1. 箭头函数的this是静态的,始终指向函数声明时所在作用域下的this的值;
  2. 不能作为构造函数实例化对象;
  3. 不能使用 arguments 变量;

代码演示及相关说明:
注意箭头函数不会更改 this 指向,用来指定回调函数会非常合适

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>箭头函数</title>
</head>

<body>
    <script>
        // ES6允许使用箭头(=>)定义函数
        // 传统写法:无参数
        var say = function () {
            console.log("hello!");
        }
        say();
        // ES6写法:无参数
        let speak = () => console.log("hello 哈哈!");
        speak();


        // 传统写法:一个参数
        var hello = function (name) {
            return "hello " + name;
        }
        console.log(hello("訾博"));
        // ES6箭头函数:一个参数
        let hi = name => "hi " + name;
        console.log(hi("訾博"));


        // 传统写法:多个参数
        var sum = function (a, b, c) {
            return a + b + c;
        }
        console.log(sum(1, 2, 3));
        // ES6箭头函数:多个参数
        let he = (a, b, c) => a + b + c;
        console.log(he(1, 2, 3));


        // 特性
        // 1、箭头函数的this是静态的,始终指向函数声明时所在作用域下的this的值
        const school = {
            name: "大哥",
        }
        // 传统函数
        function getName() {
            console.log("getName:" + this.name);
        }
        // 箭头函数
        getName1 = () => {
            console.log(this)  //window实例
            console.log("getName1:" + this.name);
        }
        window.name = "訾博";
        // // 直接调用
        getName();
        getName1();
        // // 使用call调用
        getName.call(school);
        getName1.call(school);
// 结论:箭头函数的this是静态的,始终指向函数声明时所在作用域下的this的值
// 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
    </script>
</body>

</html>

运行结果:

1644488671883

需求-1:点击 div 2s 后颜色变成『粉色』:

传统写法存在问题:
代码:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>箭头函数的实践和应用场景</title>
    <style>
        div {
            width: 200px;
            height: 200px;
            background: #58a;
        }
    </style>
</head>

<body>
    <div id="ad"></div>
    <script>
        // 需求-1 点击 div 2s 后颜色变成『粉色』
        // 获取元素
        let ad = document.getElementById('ad');
        // 绑定事件
        ad.addEventListener("click", function () {
            // 传统写法
            // 定时器:参数1:回调函数;参数2:时间;
            setTimeout(function () {
                console.log(this);  //window
                this.style.background = 'pink';
            }, 2000);
            // 报错Cannot set property 'background' of undefined
        });
    </script>
</body>
</html>

image-20220214225119801

传统写法问题解决:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>箭头函数的实践和应用场景</title>
    <style>
        div {
            width: 200px;
            height: 200px;
            background: #58a;
        }
    </style>
</head>

<body>
    <div id="ad"></div>
    <script>
        // 需求-1 点击 div 2s 后颜色变成『粉色』
        // 获取元素
        let ad = document.getElementById('ad');
        // 绑定事件
        ad.addEventListener("click", function () {
            // 传统写法
            // 保存 this 的值
            let _this = this;
            // 定时器:参数1:回调函数;参数2:时间;
            setTimeout(function () {
                console.log(this);
                _this.style.background = 'pink';
            }, 2000);
            // 报错Cannot set property 'background' of undefined
        });
    </script>
</body>

</html>

ES6写法:
(从这个案例中就能理解ES6箭头函数的特性了)

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>箭头函数的实践和应用场景</title>
    <style>
        div {
            width: 200px;
            height: 200px;
            background: #58a;
        }
    </style>
</head>

<body>
    <div id="ad"></div>
    <script>
        // 需求-1 点击 div 2s 后颜色变成『粉色』
        // 获取元素
        let ad = document.getElementById('ad');
        // 绑定事件:这也是错误写法,这里的this还是window
        // ad.addEventListener("click", () => {
        //     console.log(this);  //window
        //     // ES6写法
        //     // 定时器:参数1:回调函数;参数2:时间;
        //     setTimeout(() => this.style.background = 'pink', 2000);
        // }
        // )

        // 绑定事件
        ad.addEventListener("click", function () {
            console.log(this)  //ad
            // ES6写法
            // 定时器:参数1:回调函数;参数2:时间;
            // 这个this才是ad
            setTimeout(() => this.style.background = 'pink', 2000);
        }
        )
    </script>
</body>

</html>

需求-2 从数组中返回偶数的元素:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>箭头函数的实践和应用场景</title>
    <style>
        div {
            width: 200px;
            height: 200px;
            background: #58a;
        }
    </style>
</head>

<body>
    <div id="ad"></div>
    <script>
        // 需求-1 点击 div 2s 后颜色变成『粉色』
        // 获取元素
        let ad = document.getElementById('ad');
        // 绑定事件:这也是错误写法,这里的this还是window
        // ad.addEventListener("click", () => {
        // // ES6写法
        // // 定时器:参数1:回调函数;参数2:时间;
        // setTimeout(() => this.style.background = 'pink',2000);
        // }
        // )
        // 绑定事件
        ad.addEventListener("click", function () {
            // ES6写法
            // 定时器:参数1:回调函数;参数2:时间;
            // 这个this才是ad
            setTimeout(() => this.style.background = 'pink', 2000);
        })
        //需求-2 从数组中返回偶数的元素
        const arr = [1, 6, 9, 10, 100, 25];
        // const result = arr.filter(function(item){
        //   if(item % 2 === 0){
        //     return true;
        //   }else{
        //     return false;
        //   }
        // });
        const result = arr.filter(item => item % 2 === 0);
        console.log(result);
    // 箭头函数适合与 this 无关的回调. 定时器, 数组的方法回调
    // 箭头函数不适合与 this 有关的回调. 事件回调, 对象的方法
    </script>
</body>

</html>

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

概述:

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

代码示例及相关说明:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>函数参数默认值</title>
</head>

<body>
    <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>
</body>

</html>

8、rest参数

概述
ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments;
参考文章:https://www.jianshu.com/p/50bcb376a419

代码示例及相关说明:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>rest参数</title>
</head>

<body>
    <script>
        // ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments;
        // ES5获取实参的方式
        function data() {
            console.log(arguments);
        }
        data("大哥", "二哥", "三哥", "四哥");
        // ES6的rest参数...args,rest参数必须放在最后面(类似JAVA中的可变形参)
        function data(...args) {
            console.log(args); // fliter some every map
        }
        data("大哥", "二哥", "三哥", "四哥");
    </script>
</body>

</html>

运行结果:

image-20220214231107510

9、扩展运算符

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

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>扩展运算符</title>
</head>

<body>
    <script>
        // ... 扩展运算符能将数组转换为逗号分隔的参数序列
        //声明一个数组 ...
        const tfboys = ['易烊千玺', '王源', '王俊凯'];
        // => '易烊千玺','王源','王俊凯'
        // 声明一个函数
        function chunwan() {
            console.log(arguments);
        }
        chunwan(...tfboys); // chunwan('易烊千玺','王源','王俊凯')
    </script>
</body>

</html>

运行结果:

image-20220214231514369

应用

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>扩展运算符应用</title>
</head>

<body>
    <div id="d1"></div>
    <div id="d2"></div>
    <script>
        //1. 数组的合并 情圣 误杀 唐探
        const kuaizi = ['王太利', '肖央'];
        const fenghuang = ['曾毅', '玲花'];
        // 传统的合并方式
        // const zuixuanxiaopingguo = kuaizi.concat(fenghuang);
        const zuixuanxiaopingguo = [...kuaizi, ...fenghuang];
        console.log(zuixuanxiaopingguo);
        //2. 数组的克隆
        const sanzhihua = ['E', 'G', 'M'];
        const sanyecao = [...sanzhihua];// ['E','G','M']
        console.log(sanyecao);
        //3. 将伪数组转为真正的数组
        const divs = document.querySelectorAll('div');
        const divArr = [...divs];
        console.log(divArr); // arguments
    </script>
</body>

</html>

运行结果:

image-20220214231939535

10、Symbol

Symbol 概述:

ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型
参考文章:https://blog.csdn.net/fesfsefgs/article/details/108354248

Symbol 特点:

  1. Symbol 的值是唯一的,用来解决命名冲突的问题;
  2. Symbol 值不能与其他数据进行运算;
  3. Symbol 定义的对象属性不能使用for…in循环遍历 ,但是可以使用Reflect.ownKeys 来获取对象的所有键名;

基本使用:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>symbol</title>
</head>

<body>

    <script>
        //创建Symbol
        let s = Symbol();
        console.log(s, typeof s);
        let s2 = Symbol('尚硅谷');
        let s3 = Symbol('尚硅谷');
        console.log(s2 == s3); // false
        //Symbol.for 创建
        let s4 = Symbol.for('尚硅谷');
        let s5 = Symbol.for('尚硅谷');
        console.log(s4 == s5); // true
//不能与其他数据进行运算
//  let result = s + 100;
//  let result = s > 100;
//  let result = s + s;

// USONB -----> you are so niubility
// u undefined
// s string symbol
// o object
// n null number
// b boolean
    </script>
</body>

</html>

Symbol创建对象属性:

<!DOCTYPE html>
<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Symbol创建对象属性</title>
</head>

<body>

    <script>
        // 向对象中添加方法 up down
        let game = {
            name: '俄罗斯方块',
            up: function () { },
            down: function () { }
        };
        // 我们要往game对象里面添加方法,但是怕game对象已经存在
        // 同名方法,所以我们这时使用到了Symbol

        // 方式一
        // 声明一个对象
        let methods = {
            up: Symbol(),
            down: Symbol()
        };
        game[methods.up] = function () {
            console.log("我可以改变形状");
        }
        game[methods.down] = function () {
            console.log("我可以快速下降!!");
        }
        console.log(game);
        // 方式二
        let youxi = {
            name: "狼人杀",
            [Symbol('say')]: function () {
                console.log("我可以发言")
            },
            [Symbol('zibao')]: function () {
                console.log('我可以自爆');
            }
        }
        console.log(youxi);
        // 如何调用方法??? 讲师没讲,这是弹幕说的方法
        let say = Symbol('say');
        let youxi1 = {
            name: "狼人杀",
            [say]: function () {
                console.log("我可以发言")
            },
            [Symbol('zibao')]: function () {
                console.log('我可以自爆');
            }
        }
        youxi1[say]();

    </script>
</body>

</html>

Symbol内置值:

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

方法:

image-20220214235907046

特别的: Symbol内置值的使用,都是作为某个对象类型的属性去使用

演示

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Symbol内置属性</title>
</head>

<body>
    <script>
        class Person {
            static [Symbol.hasInstance](param) {
                console.log(param);
                console.log("我被用来检测类型了");
                return false;
            }
        }
        let o = {};
        console.log(o instanceof Person);
        const arr = [1, 2, 3];
        const arr2 = [4, 5, 6];
        // 合并数组:false数组不可展开,true可展开
        arr2[Symbol.isConcatSpreadable] = false;
        console.log(arr.concat(arr2));
    </script>
</body>

</html>

运行结果:

image-20220215000040663

11、迭代器

概述
遍历器(Iterator)就是一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作;

特性
ES6 创造了一种新的遍历命令 for...of 循环,Iterator 接口主要供 for...of 消费;

原生具备 iterator 接口的数据(可用 for of 遍历):

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

工作原理

  1. 创建一个指针对象,指向当前数据结构的起始位置;
  2. 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员;
  3. 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员;
  4. 每调用 next 方法返回一个包含 value 和 done 属性的对象;

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

代码示例及相关说明:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>迭代器</title>
</head>

<body>
    <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>
</body>

</html>

运行结果:

image-20220215083332793

迭代器自定义遍历对象:

代码实现:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>迭代器自定义遍历数据</title>
</head>

<body>
    <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);
        }
    </script>
</body>

</html>

运行结果:

image-20220215083428551

12、生成器

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

异步编程----> (之前我们用的纯回调函数都是异步编程,例如 node fs ajax mongodb)

基本使用

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>生成器</title>
</head>

<body>
    <script>
        // 生成器其实就是一个特殊的函数
        // 异步编程 纯回调函数 node fs ajax mongodb
        // yield:函数代码的分隔符
        function* gen() {
            console.log(111);
            yield '一只没有耳朵';
            console.log(222);
            yield '一只没有尾部';
            console.log(333);
            yield '真奇怪';
            console.log(444);
        }
        let iterator = gen();
        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>
</body>

</html>

运行结果:

image-20220218004215319

生成器函数的参数传递

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>生成器函数的参数传递</title>
</head>

<body>
    <script>
        function* gen(arg) {
            console.log(arg);  //"AAA"
            let one = yield 111; //{value: 111, done: false}
            console.log(one);  //"BBB"
            let two = yield 222;    //{value: 222, done: false}
            console.log(two);   //"CCC"
            let three = yield 333;  //{value: 333, done: false}
            console.log(three); //"DDD"
                                //{value: undefined, done: true}
        }
        let iterator = gen("AAA");
        console.log(iterator.next()); // 会执行yield 111;
        // next()方法是可以传入参数的,传入的参数作为上一条语句yield 的返回结果
        console.log(iterator.next("BBB")); // 会执行yield 222;
        console.log(iterator.next("CCC")); // 会执行yield 333;
        console.log(iterator.next("DDD")); // 继续往后走,未定义;
    </script>
</body>

</html>

运行结果:

image-20220218005038138

生成器函数实例1:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>生成器函数实例1</title>
</head>

<body>
    <script>
        // 异步编程 文件操作 网络操作(ajax,request) 数据库操作
        // 需求:1s后控制台输出111 再过2s后控制台输出222 再过3s后控制台输出333
        // 一种做法:回调地狱
        // setTimeout(()=>{
        // console.log(111);
        // setTimeout(()=>{
        // console.log(222);
        // setTimeout(()=>{
        // console.log(333);
        // },3000)
        // },2000)
        // },1000)
        // 另一种做法
        function one() {
            setTimeout(() => {
                console.log(111);
                iterator.next();
            }, 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();
    </script>
</body>

</html>

运行结果:

image-20220218005442635

生成器函数实例2:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>生成器函数实例2</title>
</head>

<body>
    <script>
        // 模拟获取: 用户数据 订单数据 商品数据
        function getUsers() {
            setTimeout(() => {
                let data = "用户数据";
                // 第二次调用next,传入参数,作为第一个的返回值
                iterator.next(data); // 这里将data传入
            }, 1000);
        }
        function getOrders() {
            setTimeout(() => {
                let data = "订单数据";
                iterator.next(data); // 这里将data传入
            }, 1000);
        }
        function getGoods() {
            setTimeout(() => {
                let data = "商品数据";
                iterator.next(data); // 这里将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();
    </script>
</body>

</html>

运行结果:

image-20220218010023363

13、Promise

概述:

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

Promise实现了以同步书写方式完成了异步回调功能

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

基本使用:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Promise</title>
</head>

<body>
    <script>
        // 实例化 Promise 对象
        // Promise 对象三种状态:初始化、成功、失败
        const p = new Promise(function (resolve, reject) {
            setTimeout(function () {
                // 成功
                // let data = "数据";
                // 调用resolve方法,表示成功,这个Promise 对象的状态就会变成成功----》然后执行下面Promise对象的then方法中的第一个回调函数
                // 调用reject方法,表示失败,这个Promise 对象的状态就会变成失败----》然后执行下面Promise对象的then方法中的第二个回调函数
                // resolve(data);


                // 失败
                let err = "失败了!";
                reject(err);
            }, 1000);
        });
        
        // 调用 Promise 对象的then方法,两个参数为函数,
        //当Promise对象的状态为成功时,执行第一个回调函数;
        //当Promise对象的状态为失败时,执行第二个回调函数;
        p.then(function (success) { // 成功
            console.log(success);
        }, function (error) { // 失败
            console.log(error);
        });
    </script>
</body>

</html>

如下图

image-20220218225410214

Promise封装读取文件:

一般写法:

2-Promise封装读取文件.js:

//1. 引入 fs 模块(这是node的模块,如果还没学nodejs知识,可以先跳过)
const fs = require('fs');

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

//3. 使用 Promise 封装
const p = new Promise(function (resolve, reject) {
    //读取文件
    fs.readFile("./resources/为学.md", (err, data) => {
        //判断如果失败
        if (err) reject(err);
        //如果成功
        resolve(data);
    });
});

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

resources/为学.md文件:

   为学
天下事有难易乎?
为之,则难者亦易矣;
不为,则易者亦难矣

执行:

node 2-Promise封装读取文件.js

执行结果:

image-20220218235843395

Promise封装Ajax请求:

原生请求:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>发送 AJAX 请求</title>
</head>

<body>
    <script>
        // 接口地址: https://api.apiopen.top/getJoke
        const p = new Promise((resolve, reject) => {
            //1. 创建对象
            const xhr = new XMLHttpRequest();

            //2. 初始化
            xhr.open("GET", "https://api.apiopen.top/getJ");

            //4. 发送
            xhr.send();

            //3. 绑定事件, 处理响应结果
            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.error(reason);
        });
    </script>
</body>

</html>

image-20220219001225857

Promise.prototype.then:

代码实现及相关说明:

1、如果then中的回调函数返回的结果是 非promise 类型的数据
<script>
        // 创建 Promise 对象
        const p = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve("用户数据");
            }, 1000);
        });
        // 调用then方法,then方法的返回结果是promise对象,
        // 对象的状态由then中回调函数的结果决定;
        const result = p.then(value => {
            console.log(value);
            // 1、如果回调函数中返回的结果是 非promise 类型的数据,
            // then方法返回的Promise对象的状态[[PromiseState]]为resolved或者fulfilled,返回值[[PromiseResult]]为回调函数的返回值,这个例子中,由于回调函数return 123,所以[[PromiseResult]]=123
            return 123;

        }, reason => {
            console.error(reason);
        })

        console.log(result);


    </script>

运行结果:

image-20220219010109090

2、如果回调函数返回的是promise类型的数据

​ 2.1、回调函数----》返回的Promise对象中----》调用reject方法

    <script>
        // 创建 Promise 对象
        const p = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve("用户数据");
            }, 1000);
        });
        // 调用then方法,then方法的返回结果是promise对象,
        // 对象的状态由then中的回调函数的结果决定;
        const result = p.then(value => {
            console.log(value);
           

            // 2、如果回调函数返回的是promise类型的数据
            // 此Promise对象的状态决定上面Promise对象p的状态
            return new Promise((resolve,reject)=>{
            // resolve("ok"); // resolved
            	reject("ok"); // rejected
            });

          
        }, reason => {
            console.error(reason);
        })

        console.log(result);

        
    </script>

运行结果

image-20220219010633374

理解:

1645583100881

2.2、回调函数----》返回的Promise对象中----》调用resovled方法

    <script>
        // 创建 Promise 对象
        const p = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve("用户数据");
            }, 1000);
        });
        // 调用then方法,then方法的返回结果是promise对象,
        // 对象的状态由then中回调函数的结果决定;
        const result = p.then(value => {
            console.log(value);
           

            // 2、如果回调函数返回的是promise类型的数据
            // 此Promise对象的状态决定上面Promise对象p的状态
            return new Promise((resolve,reject)=>{
             resolve("ok"); // resolved
            //	reject("ok"); // rejected
            });

          
        }, reason => {
            console.error(reason);
        })

        console.log(result);
   
    </script>

运行结果:

image-20220219010812500

3、抛出错误的情况,返回的Promise对象中----》[[PromiseState]]: "rejected" ----》[[PromiseResult]]---》异常抛出的值

    <script>
        // 创建 Promise 对象
        const p = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve("用户数据");
            }, 1000);
        });
        // 调用then方法,then方法的返回结果是promise对象,
        // 对象的状态由then中的回调函数的结果决定;
        const result = p.then(value => {
            console.log(value);
            
            // 3、抛出错误
            throw new Error("失败啦!");

        }, reason => {
            console.error(reason);
        })

        console.log(result);

    </script>

运行结果:

image-20220219011342551

Promise链式调用
// 链式调用
// then里面两个函数参数,可以只写一个
p.then(value => { }, reason => { }).then(value => { }, reason => { });
console.log(result);
Promise对象catch方法:

image-20220219112025002

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>catch方法</title>
</head>

<body>
    <script>
        const p = new Promise((resolve, reject) => {
            setTimeout(() => {
                //设置 p 对象的状态为失败, 并设置失败的值
                reject("出错啦!");
               
            }, 1000)
        });

        // p.then(function(value){}, function(reason){
        //     console.error(reason);
        // });

        p.catch(function (reason) {
            console.warn(reason);
        });
    </script>
</body>

</html>

运行结果

image-20220219111602656

14、Set集合

概述:

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

  1. size 返回集合的元素个数;
  2. add 增加一个新元素,返回当前集合;
  3. delete 删除元素,返回 boolean 值;
  4. has 检测集合中是否包含某个元素,返回 boolean 值;
  5. clear 清空集合,返回 undefined;

基本使用:

代码实现:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Set集合</title>
</head>

<body>
    <script>
        // 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);
    </script>
</body>

</html>

运行结果:

image-20220219113057626

Set集合实践:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Set 实践</title>
</head>

<body>
    <script>
        let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1];
        //1. 数组去重
        // new Set(arr)可将其转换为类数组(相当于集合),且里面的元素是不重复的---》接着用扩展运算符... 将类数组转换成---》用逗号分隔的参数序列---》最后用 中括号[] 把参数序列包起来,变成了数组
        // let result = [...new Set(arr)];
        // console.log(result);

        //2. 交集
        let arr2 = [4, 5, 6, 5, 6];
        // let result = [...new Set(arr)].filter(item => {
        //     let s2 = new Set(arr2);// 4 5 6
        //     if(s2.has(item)){
        //         return true;
        //     }else{
        //         return false;
        //     }
        // });

        //简写:
        // let result = [...new Set(arr)].filter(item => new Set(arr2).has(item));
        // console.log(result);

        //3. 并集
        // 先合并再去重   
        // 合并:[...arr, ...arr2]
        // 去重:new Set([...arr, ...arr2])
        // 变成数组:[...new Set([...arr, ...arr2])]
        // let union = [...new Set([...arr, ...arr2])];
        // console.log(union);

        //4. 差集
        let diff = [...new Set(arr)].filter(item => !(new Set(arr2).has(item)));
        console.log(diff);

    </script>
</body>

</html>

15、Map集合

概述:

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

Map 的属性和方法:

  1. size 返回 Map 的元素个数;
  2. set 增加一个新元素,返回当前 Map;
  3. get 返回键名对象的键值;
  4. has 检测 Map 中是否包含某个元素,返回 boolean 值;
  5. clear 清空集合,返回 undefined;

简单使用:

代码实现:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Map集合</title>
</head>

<body>
    <script>
        // Map集合
        // 创建一个空 map
        let m = new Map();
        // 创建一个非空 map
        let m2 = new Map([
            ['name', '尚硅谷'],
            ['slogon', '不断提高行业标准']
        ]);
        // console.log(m2);
        // console.log(m2.size);
        // console.log(m2.get('name'));

        // 1. size 返回 Map 的元素个数;
        console.log(m2.size);
        // 2. set 增加一个新元素,返回当前 Map;
        m.set("皇帝", "大哥");
        m.set("丞相", "二哥");
        console.log(m);
        // 3. get 返回键名对象的键值;
        console.log(m.get("皇帝"));
        // 4. has 检测 Map 中是否包含某个元素,返回 boolean 值;
        console.log(m.has("皇帝"));


        //5.遍历
        for (let v of m) {
            console.log(v);
        }
        // 6. clear 清空集合,返回 undefined;
        m.clear();
        console.log(m);
    </script>
</body>

</html>

运行结果:

image-20220219122154091

16、class类

概述:

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

知识点:

  1. class 声明类;
  2. constructor 定义构造函数初始化;
  3. extends 继承父类;
  4. super 调用父级构造方法;
  5. static 定义静态方法和属性;
  6. 父类方法可以重写;

class初体验:

代码实现:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>类声明</title>
</head>

<body>
    <script>
        //手机
        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);

        //class
        class Shouji {
            //构造方法 名字constructor不能修改
            constructor(brand, price) {
                this.brand = brand;
                this.price = price;
            }

            //方法必须使用该语法, 不能使用 ES5 的对象完整形式,以下的写法是错误的
            //  call: function(){}

            call() {
                console.log("我可以打电话!!");
            }
        }

        let onePlus = new Shouji("1+", 1999);

        console.log(onePlus);
    </script>
</body>

</html>

运行结果:

image-20220219150227776

class静态成员:

注意:静态属性,属于类的属性,不属于实例对象的属性,所以可以用 类.xxx访问静态属性,不能用实例对象.xxx访问静态属性

代码实现:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>静态成员</title>
</head>

<body>
    <script>
        // function Phone(){

        // }
        // Phone.name = '手机';
        // Phone.change = function(){
        //     console.log("我可以改变世界");
        // }
        // Phone.prototype.size = '5.5inch';

        // let nokia = new Phone();

        // console.log(nokia.name);
        // // nokia.change();
        // console.log(nokia.size);

        class Phone {
            //静态属性,属于类的属性,不属于实例对象的属性,所以可以用 '类.xxx'访问静态属性,不能用'实例对象.xxx'访问静态属性
            static name = '手机';
            static change() {
                console.log("我可以改变世界");
            }
        }

        let nokia = new Phone();
        console.log(nokia.name);   //undefined
        console.log(Phone.name);    //手机
    </script>
</body>

</html>

ES5构造函数实现继承:

代码实现:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>对象继承</title>
</head>

<body>
    <script>
        //手机
        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.color = color;
            this.size = size;
        }

        //设置子级构造函数的原型
        //子级构造函数的显性原型指向父级的实例对象===》子类的原型=父类的实例对象
        //让子级构造函数的显性原型对象中的constructor属性指向子级构造函数(此处说得又得拗口,不懂的可以看原型链知识)
        SmartPhone.prototype = new Phone();
        SmartPhone.prototype.constructor = SmartPhone;

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

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

        const chuizi = new SmartPhone('锤子', 2499, '黑色', '5.5inch');

        console.log(chuizi);

    </script>
</body>

</html>

运行结果:

image-20220219152902435

ES6class类继承:

代码实现:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>类继承-2</title>
</head>

<body>
    <script>
        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);// Phone.call(this, brand, price)
                this.color = color;
                this.size = size;
            }

            photo() {
                console.log("拍照");
            }

            playGame() {
                console.log("玩游戏");
            }

            //重写父类的方法
            call() {
                console.log('我可以进行视频通话');
            }
        }

        const xiaomi = new SmartPhone('小米', 799, '黑色', '4.7inch');
        // console.log(xiaomi);
        xiaomi.call();
        xiaomi.photo();
        xiaomi.playGame();
    </script>
</body>

</html>

运行结果:

image-20220219153652940

17、数值扩展

Number.EPSILON:Number.EPSILON 是 JavaScript 表示的最小精度;
EPSILON 属性的值接近于 2.2204460492503130808472633361816E-16;如果俩个数相减的绝对值小于Number.EPSILON,则认为这俩个数是相等的

二进制和八进制
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() 用来判断一个数值是否为整数;

代码实现和相关说明:
代码实现:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>数值扩展</title>
</head>

<body>
    <script>
        //0. Number.EPSILON 是 JavaScript 表示的最小精度
        //EPSILON 属性的值接近于 2.2204460492503130808472633361816E-16
        // function equal(a, b){
        //     if(Math.abs(a-b) < Number.EPSILON){  //如果俩个数相减的绝对值小于Number.EPSILON,则认为这俩个数是相等的
        //         return true;
        //     }else{
        //         return false;
        //     }
        // }
        // console.log(0.1 + 0.2 === 0.3);   //false 由于计算机底层是用二进制计算的,0.1+0.2是不等于0.3
        // console.log(equal(0.1 + 0.2, 0.3))

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

        //2. Number.isFinite  检测一个数值是否为有限数,只能检查number类型,且不转换
        // console.log(Number.isFinite(100));   true
        // console.log(Number.isFinite(100/0));     false
        // console.log(Number.isFinite(100 / 3));   //true(这个我也不知道为什么返回true)
        // console.log(Number.isFinite(Infinity));  false
        // console.log(Number.isFinite('abc'));  false
        // console.log(Number.isFinite('123'));  false


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


        //4. Number.parseInt Number.parseFloat字符串转整数
        // console.log(Number.parseInt('5211314love'));
        // console.log(Number.parseFloat('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));

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

    </script>
</body>

</html>

18、对象扩展

概述:

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

  1. Object.is 比较两个值是否严格相等,与『===』行为基本一致(+0 与 NaN);
  2. Object.assign 对象的合并,将源对象的所有可枚举属性,复制到目标对象;
  3. proto、setPrototypeOf、 setPrototypeOf 可以直接设置对象的原型;

代码实现及相关说明:

代码实现:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>对象扩展</title>
</head>

<body>
    <script>
        // 对象扩展
        // 1. Object.is 比较两个值是否严格相等,与『===』行为基本一致(+0 与 NaN);
        console.log(Object.is(120, 120)); // true
        // 注意下面的区别
        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: ['北京', '上海', '深圳']
        }
        //cities对象赋值给school对象的原型
        // 并不建议这么做
        Object.setPrototypeOf(school, cities);
        console.log(Object.getPrototypeOf(school));
        console.log(school);
    </script>
</body>

</html>

19、模块化

概述:

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

模块化的好处:

模块化的优势有以下几点:

  1. 防止命名冲突;
  2. 代码复用;
  3. 高维护性;

模块化规范产品:

ES6 之前的模块化规范有:

  1. CommonJS(只是一种规范) =>(规范的实现) NodeJS、Browserify;
  2. AMD(只是一种规范) =>(规范的实现) requireJS;
  3. CMD(只是一种规范) => (规范的实现) seaJS;

ES6 模块化语法:

模块功能主要由两个命令构成:export 和 import;
export 命令用于规定模块的对外接口(导出模块);
import 命令用于输入其他模块提供的功能(导入模块);

ES6暴露数据方式:

逐个导出模块:

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("我们可以帮你改变人生!");
}
}

模块化.html(引入和使用模块)

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>模块化</title>
</head>

<body>
    <script type="module">
        // 引入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();
    </script>
</body>

</html>

运行结果:

image-20220219172545537

ES6导入模块语法汇总:

模块化.html:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ES6 模块化</title>
</head>

<body>
    <script type="module">
        //1. 通用的导入方式
        //引入 m1.js 模块内容
        // import * as m1 from "./src/js/m1.js";
        // //引入 m2.js 模块内容
        // import * as m2 from "./src/js/m2.js";
        // //引入 m3.js
        // import * as m3 from "./src/js/m3.js";

        //2. 解构赋值形式
        //注意:{}中的变量名要么等于暴露的js模块中的变量,要么,给{}中的变量名起别名
        // import { school, teach } from "./src/js/m1.js";
        // import {school as guigu, findJob} from "./src/js/m2.js";   //给{}中的变量名起别名
        // import {default as m3} from "./src/js/m3.js";

        //3. 简便形式  针对默认暴露,即 export defalut{}这种模块
        // import m3 from "./src/js/m3.js";
        // console.log(m3);
    </script>

</body>

</html>

image-20220219174518162

image-20220219174601086

image-20220219174632589

使用模块化的另一种方式:

将js语法整合到一个文件app.js:

// 通用方式
// 引入m.js模块内容
import * as m from "./m.js";
console.log(m);
console.log(m.school);
m.teach();

使用模块化的另一种方式.html:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>使用模块化的另一种方式</title>
	</head>
	<body>
		<script src="./js/app.js" type="module"></script>
	</body>
</html>

运行结果:

image-20220219175338358

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

Babel概述:

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

步骤:

使用Babel转换JS代码——打包成一个文件——使用时引入即可;

第一步:安装工具babel-cli(命令行工具) babel-preset-env(ES转换工具) browserify(打包工具,项目中使用的是webpack);

npm i babel-cli babel-preset-env browserify -D

第二步:初始化项目

npm init -y

第三步:使用babel转换

npx babel js目录 -d 转化后的js目录 --presets=babel-preset-env

例:

npx babel src/js -d dist/js --presets=babel-preset-env

第四步:打包

npx browserify 需要打包的js文件,一般是入口文件且已经被第三步babel编译过的文件 -o 打包后的文件路径

例:dist目录下的app.js是编译过后的文件

npx browserify dist/js/app.js -o dist/bundle.js

第五步:在使用时引入打包好的js文件:bundle.js

<script src="./js/bundle.js" type="module"></script>

转换前后对比:
转换前:

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

转换后:

"use strict";
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.teach = teach;
//分别暴露
var school = exports.school = '尚硅谷';
function teach() {
  console.log("我们可以教给你开发技能");
}

21、ES6模块化引入NPM包

演示:
第一步:安装jquery:

npm i jquery

第二步:在app.js使用jquery

//入口文件
//修改背景颜色为粉色
import $ from 'jquery';// 相当于const $ = require("jquery");
$('body').css('background','pink');

三、ES7 新特性

功能概述

1、Array.prototype.includes

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

2、指数操作符

幂运算的简化写法,例如:2的10次方:2**10;

1、Array.prototype.includes

概述:
Includes 方法用来检测数组中是否包含某个元素,返回布尔类型值;
判断数组中是否包含某元素,语法:arr.includes(元素值);

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>includes</title>
</head>

<body>
    <script>
        // includes
        let arr = [1, 2, 3, 4, 5];
        console.log(arr.includes(1));
    </script>
</body>

</html

运行结果

image-20220219223453907

2、指数操作符

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

代码实现:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>指数操作符</title>
</head>

<body>
    <script>
        // 指数操作符
        console.log(Math.pow(2, 10))
        console.log(2 ** 10);
    </script>
</body>

</html>

运行结果

image-20220219223713784

四、ES8 新特性

功能概述

1、async 和 await
​ 简化异步函数的写法;

2、对象方法扩展
​ 对象方法扩展;

1、async 和 await

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

async 函数:

概述:

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

代码实现:

情况1: async函数体返回的结果不是一个 Promise 类型的对象, 那么我们得到async函数的最终结果就是成功 的Promise 对象

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>async函数</title>
</head>

<body>
    <script>
        //async 函数
        async function fn() {


            // 情况1:返回的结果不是一个 Promise 类型的对象, 返回的结果就是成功 Promise 对象
            // return;
            return '尚硅谷';

        }

        const result = fn();
        console.log(result);  //返回一个Promise对象

        //调用 then 方法
        result.then(value => {
            console.log(value);
        }, reason => {
            console.warn(reason);
        })
    </script>
</body>

</html>

运行结果:

image-20220219224616877

情况2:抛出错误, 返回的结果是一个失败的 Promise

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>async函数</title>
</head>

<body>
    <script>
        //async 函数
        async function fn() {
            //情况2:抛出错误, 返回的结果是一个失败的 Promise
            throw new Error('出错啦!');

        }

        const result = fn();
        console.log(result);  //返回一个Promise对象

        //调用 then 方法
        result.then(value => {
            console.log(value);
        }, reason => {
            console.warn(reason);
        })
    </script>
</body>

</html>

运行结果:

image-20220219224855106

情况3:返回的结果如果是一个 Promise 对象,如果这个Promise对象中执行了resolve方法,则返回成功的Promise对象;反之亦然

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>async函数</title>
</head>

<body>
    <script>
        //async 函数
        async function fn() {
       //情况3:返回的结果如果是一个 Promise 对象,如果这个Promise对象中执行了resolve方法,则返回成功的Promise对象;反之亦然
            return new Promise((resolve, reject)=>{
                resolve('成功的数据');
                // reject("失败的错误");
            });
        }

        const result = fn();
        console.log(result);  //返回一个Promise对象

        //调用 then 方法
        result.then(value => {
            console.log(value);
        }, reason => {
            console.warn(reason);
        })
    </script>
</body>

</html>

运行结果

image-20220219225025182

await 表达式:

概述:

  1. await 必须写在 async 函数中,但是async函数中可以没有await;
  2. await 右侧的表达式一般为 promise 对象,await 返回的是 promise 成功的值;;如果await右侧的表达式是其他值,直接将此值作为await的返回值
  3. await 的 promise 失败了, 就会抛出异常, 需要通过 try...catch 捕获处理;

代码实现:

返回成功的案例:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>await</title>
</head>

<body>
    <script>
        //创建 promise 对象
        const p = new Promise((resolve, reject) => {
            resolve("用户数据");
            // reject("失败啦!");
        })

        // await 要放在 async 函数中.
        async function main() {
            try {
                let result = await p;
                console.log(result);
            } catch (e) {
                console.log(e);
            }
        }
        //调用函数
        main();
    </script>
</body>

</html>

运行结果:

image-20220219232110620

返回失败的案例:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>await</title>
</head>

<body>
    <script>
        //创建 promise 对象
        const p = new Promise((resolve, reject) => {
            //resolve("用户数据");
             reject("失败啦!");
        })

        // await 要放在 async 函数中.
        async function main() {
            try {
                let result = await p;
                console.log(result);
            } catch (e) {
                console.log(e);
            }
        }
        //调用函数
        main();
    </script>
</body>

</html>

运行结果:

image-20220219232303680

async 和 await 读取文件案例:

代码实现:

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

//读取『为学』
function readWeiXue() {
    return new Promise((resolve, reject) => {
        fs.readFile("./resources/为学.md", (err, data) => {
            //如果失败
            if (err) reject(err);
            //如果成功
            resolve(data);
        })
    })
}

function readChaYangShi() {
    return new Promise((resolve, reject) => {
        fs.readFile("./resources/插秧诗.md", (err, data) => {
            //如果失败
            if (err) reject(err);
            //如果成功
            resolve(data);
        })
    })
}

function readGuanShu() {
    return new Promise((resolve, reject) => {
        fs.readFile("./resources/观书有感.md", (err, data) => {
            //如果失败
            if (err) reject(err);
            //如果成功
            resolve(data);
        })
    })
}

//声明一个 async 函数
async function main() {
    try {
        //获取为学内容
        let weixue = await readWeiXue();
        //获取插秧诗内容
        let chayang = await readChaYangShi();
        // 获取观书有感
        let guanshu = await readGuanShu();
        console.log(weixue.toString());
        console.log(chayang.toString());
        console.log(guanshu.toString());
    } catch (error) {
        console.log(error);
    }
}

main();

运行结果:

image-20220219233447576

async 和 await 结合发送ajax请求:

代码实现:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>发送 AJAX 请求</title>
</head>

<body>
    <script>
        // 发送 AJAX 请求, 返回的结果是 Promise 对象
        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);
                        }
                    }
                }
            })
        }

        //promise then 方法测试
        // sendAJAX("https://api.apiopen.top/getJoke").then(value=>{
        //     console.log(value);
        // }, reason=>{})

        // async 与 await 测试 
        async function main() {
            //发送 AJAX 请求
            let result = await sendAJAX("https://api.apiopen.top/getJoke");
            //再次测试
            let tianqi = await sendAJAX('https://www.tianqiapi.com/api/?version=v1&city=%E5%8C%97%E4%BA%AC&appid=23941491&appsecret=TXoD5e8P')

            console.log(tianqi);
        }

        main();

    </script>
</body>

</html>

运行结果:

image-20220219234856157

2、对象方法扩展

Object.values、Object.entries和Object.getOwnPropertyDescriptors:

  1. Object.values()方法:返回一个给定对象的所有可枚举属性值的数组
  2. Object.entries()方法:返回一个给定对象自身可遍历属性 [key,value] 的数组(也可以这样理解:将对象转为二维数组);
  3. Object.getOwnPropertyDescriptors()该方法:返回指定对象所有自身属性的描述对象;

代码实现:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ES8 对象方法扩展</title>
</head>

<body>
    <script>
        //声明对象
        const school = {
            name: "尚硅谷",
            cities: ['北京', '上海', '深圳'],
            xueke: ['前端', 'Java', '大数据', '运维']
        };

        //获取对象所有的键
        console.log(Object.keys(school));
        //获取对象所有的值
        console.log(Object.values(school));
        //entries
        console.log(Object.entries(school));
        //创建 Map
        const m = new Map(Object.entries(school));
        console.log(m.get('cities'));

        //对象属性的 描述对象
        console.log(Object.getOwnPropertyDescriptors(school));

        // const obj = Object.create(null, {
        //     name: {
        //         //设置值
        //         value: '尚硅谷',
        //         //属性特性
        //         writable: true,
        //         configurable: true,
        //         enumerable: true
        //     }
        // });
    </script>
</body>

</html>

运行结果:

image-20220220000843684

对Object.getOwnPropertyDescriptors(对象名)的理解:

image-20220220001022939

五、ES9 新特性

功能概述

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

​ 在对象中使Rest参数与spread扩展运算符;

2、正则扩展
​ 简化和增强正则匹配;

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

概述:

Rest 参数与 spread 扩展运算符在 ES6 中已经引入,不过 ES6 中只针对于数组,在 ES9 中为对象提供了像数组一样的 rest 参数和扩展运算符;

代码实现:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>对象展开</title>
</head>

<body>
    <!-- 
        Rest 参数与 spread 扩展运算符在 ES6 中已经引入,不过 ES6 中只针对于数组,
        在 ES9 中为对象提供了像数组一样的 rest 参数和扩展运算符
     -->
    <script>
        //spread 扩展运算符
        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'
        });



        // Rest 参数
        // ...skillOne   =>  q: '天音波', w: '金钟罩'
        const skillOne = {
            q: '天音波'
        }

        const skillTwo = {
            w: '金钟罩'
        }

        const skillThree = {
            e: '天雷破'
        }
        const skillFour = {
            r: '猛龙摆尾'
        }

        //对象合并
      const mangseng = { ...skillOne, ...skillTwo, ...skillThree, ...skillFour };

        console.log(mangseng)

        // ...skillOne   =>  q: '天音波', w: '金钟罩'

    </script>

</body>

</html>

运行结果:

image-20220220002552516

2、正则扩展:命名捕获分组

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

代码实现:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>正则扩展-命名捕获分组</title>
</head>

<body>
    <script>
        // 正则扩展:命名捕获分组
        // 声明一个字符串
        let str = '<a href="http://www.baidu.com">訾博</a>';
        // 需求:提取url和标签内文本
        // 之前的写法
        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);
    </script>
</body>

</html>

运行结果:

image-20220220004344165

3、正则扩展:反向断言

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

代码实现:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>正则扩展-反向断言</title>
</head>
<body>
    <script>
        //声明字符串
        let str = 'JS5211314你知道么555啦啦啦';
        //正向断言:从左到右判断条件在右边,例如(?=啦)
        var reg = /\d+(?=啦)/;
        var result = reg.exec(str);
        console.log(result)

        //反向断言:从左到右判断条件在左边,例如(?<=么)
        var reg = /(?<=么)\d+/;
        var result = reg.exec(str);
        console.log(result);
    </script>
</body>
</html>

运行结果:

image-20220220005336158

4、正则扩展:dotAll 模式

概述:
正则表达式中点.匹配除回车外的任何单字符,标记/s改变这种行为,包括换行符(\n);

代码实现:

情况1:没有 模式修正符的情况:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>正则扩展-dotAll模式</title>
</head>

<body>
    <script>
        //dot  .  元字符  除换行符以外的任意单个字符
        let str = `
        <ul>
            <li>
                <a>肖生克的救赎</a>
                <p>上映日期: 1994-09-10</p>
            </li>
            <li>
                <a>阿甘正传</a>
                <p>上映日期: 1994-07-06</p>
            </li>
        </ul>`;
        //声明正则
         var reg = /<li>\s+<a>(.*?)<\/a>\s+<p>(.*?)<\/p>/;
         var result = reg.exec(str);
         console.log(result)
    </script>
</body>

</html>

运行结果:

image-20220220115529257

虽然结果能出来,但是不建议这样匹配,如果字符串比较复杂,那么正则表达式就比较复杂且臃肿

例如字符串多加了span元素,那么正则表示式也要做相应的处理:

 let str = `
        <ul>
            <li>
				<span></span>
                <a>肖生克的救赎</a>
                <p>上映日期: 1994-09-10</p>
            </li>
            <li>
                <a>阿甘正传</a>
                <p>上映日期: 1994-07-06</p>
            </li>
        </ul>`;
var reg = /<li>\s+<span>.*?<\/span>\s+<a>(.*?)<\/a>\s+<p>(.*?)<\/p>/;

由此可见,没有模式修正符的情况下,是不理想的

情况2:模式修正符的情况:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>正则扩展-dotAll模式</title>
</head>

<body>
    <script>
        //dot  .  元字符  除换行符以外的任意单个字符
        let str = `
        <ul>
            <li>
                <a>肖生克的救赎</a>
                <p>上映日期: 1994-09-10</p>
            </li>
            <li>
                <a>阿甘正传</a>
                <p>上映日期: 1994-07-06</p>
            </li>
        </ul>`;
        //声明正则

        // 再量词*后面直接加问号?----》懒惰匹配;
        //  /regexp/s----》模式中的圆点元字符(.)匹配任何字符,包括换行符(\n)
        var reg = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/gs;
        //执行匹配
        // const result = reg.exec(str);
        let result;
        let data = [];
        while (result = reg.exec(str)) {

            data.push({ title: result[1], time: result[2] });
        }
        //输出结果
        console.log(data);


    </script>
</body>

</html>

运行结果:

image-20220220122951701

正则表达式的解释:

image-20220220122823976

六、ES10 新特性

功能概述

1、Object.fromEntries:将二维数组或者map转换成对象;

2、trimStart 和 trimEnd: 去除字符串前后的空白字符;

3、Array.prototype.flat 与 flatMap : 将多维数组降维;

4、Symbol.prototype.description: 获取Symbol的字符串描述;

1、Object.fromEntries

概述:

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

代码实现:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Object.fromEntries</title>
</head>

<body>
    <script>
        //二维数组 --->对象
        var result = Object.fromEntries([
            ['name', '尚硅谷'],
            ['xueke', 'Java,大数据,前端,云计算']
        ]);
        console.log(result)

        // Map
        var m = new Map();
        m.set('name', 'ATGUIGU');
        console.log(m);
        //map---->对象
        result = Object.fromEntries(m);
        console.log(result);

        //Object.entries ES8
        // 对象---》二维数组
        var arr = Object.entries({
            name: "尚硅谷"
        })
        console.log(arr);
    </script>
</body>

</html>

运行结果:

image-20220220142530571

2、trimStart 和 trimEnd

概述:
去掉字符串前后的空白字符;

代码实现:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>trimStart 与 trimEnd</title>
</head>
<body>
    <script>    
        // trim
        let str = '   iloveyou   ';

        console.log(str);
        console.log(str.trimStart());
        console.log(str.trimEnd());
    </script>
</body>
</html>

运行结果:

image-20220220142702812

3、Array.prototype.flat 与 flatMap

概述:
将多维数组转换成低维数组;

代码实现:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>flat 与 flatMap</title>
</head>

<body>
    <script>
        //将多维数组转化为低位数组
        var arr = [1, 2, 3, 4, [5, 6]];
        console.log(arr.flat());

        var arr = [1, 2, 3, 4, [5, 6, [7, 8, 9]], [10, 11]];
        //参数为深度 是一个数字,默认为1
        // 如果参数为2,能解析三维数组;如果参数为3,能解析四维数组
        console.log(arr.flat(2));

        //flatMap
        //数组对象的map方法,可以返回一个新的数组,关键在于返回的值,且不改变元素
        var arr = [1, 2, 3, 4];
        var result = arr.map(item => item * 10);
        console.log(result);

        //数组对象的map方法,此时返回一个二维数组
        result = arr.map(item => [item * 10]);
        console.log(result);

        // flatMap,将高维数组降为低维数组
        result = arr.flatMap(item => [item * 10]);
        console.log(result);
    </script>
</body>

</html>

运行结果:

image-20220220144231937

4、Symbol.prototype.description

概述:
获取Symbol的描述字符串;

代码实现:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Symbol.prototype.description</title>
</head>

<body>
    <script>
        //创建 Symbol
        let s = Symbol('尚硅谷');

        console.log(s.description);  //尚硅谷
    </script>
</body>

</html>

七、ES11 新特性

功能概述

1、String.prototype.matchAll:用来得到正则批量匹配的结果;

2、类的私有属性:私有属性外部不可访问直接;

3、Promise.allSettled:获取多个promise执行的结果集;

4、可选链操作符:简化对象存在的判断逻辑;

5、动态 import 导入:动态导入模块,什么时候使用什么时候导入;

6、BigInt:大整型;

7、globalThis 对象:始终指向全局对象window;

1、String.prototype.matchAll

概述:
用来得到正则批量匹配的结果;

代码实现:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>String.prototype.matchAll</title>
</head>

<body>
    <script>
        let str = `<ul>
            <li>
                <a>肖生克的救赎</a>
                <p>上映日期: 1994-09-10</p>
            </li>
            <li>
                <a>阿甘正传</a>
                <p>上映日期: 1994-07-06</p>
            </li>
        </ul>`;

        //声明正则
        var reg = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/sg

        //调用方法
        var result = str.matchAll(reg);

        // 返回的是可迭代对象,可用扩展运算符展开
        var arr = [...result];
        console.log(arr);

        // 返回的是可迭代对象,可用也可用for...of循环遍历
        // for (let v of result) {
        //     console.log(v);
        // }




    </script>
</body>

</html>

运行结果:

image-20220220160531437

2、类的私有属性

概述:
私有属性外部不可访问直接;

代码实现:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>私有属性</title>
</head>

<body>
    <script>
        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, '45kg');

        // console.log(girl.name);
        // console.log(girl.#age); //Uncaught SyntaxError: Private field '#age' must be declared in an enclosing class
        // console.log(girl.#weight);

        //girl.intro();
    </script>
</body>

</html>

3、Promise.allSettled

概述:
获取多个promise执行的结果集;
代码实现:

情况1: 参数都是返回成功状态

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Promise.allSettled</title>
</head>

<body>
    <script>
        //声明两个promise对象
        const p1 = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('商品数据 - 1');
            }, 1000)
        });

        const p2 = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('商品数据 - 2');
                // reject('出错啦!');
            }, 1000)
        });

        //调用 allsettled 方法,始终返回状态为resolve/fulfilled的Promise的对象,且这个Promise对象的PromiseResult值包含参数对象的状态和值
        
        //情况1:参数p1,p2都是返回成功状态
        var result = Promise.allSettled([p1, p2]);
        console.log(result);

    </script>
</body>

</html>

运行结果:

image-20220220151538295

情况2: 有参数返回失败状态

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Promise.allSettled</title>
</head>

<body>
    <script>
        //声明两个promise对象
        const p1 = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('商品数据 - 1');
            }, 1000)
        });

        const p2 = new Promise((resolve, reject) => {
            setTimeout(() => {
                // resolve('商品数据 - 2');
                reject('出错啦!');
            }, 1000)
        });

        //调用 allsettled 方法,始终返回状态为resolve/fulfilled的Promise的对象,且这个Promise对象的PromiseResult值包含参数对象的状态和值
        
        //情况2:参数p1返回成功状态,p2返回失败状态
        var result = Promise.allSettled([p1, p2]);
        console.log(result);
    </script>
</body>

</html>

运行结果:

image-20220220151710070

情况3: 和Promise.all()方法的对比

​ 情况3-1:若参数对象都返回成功的状态,能正确执行并能得到参数对象中resolved的值

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Promise.allSettled</title>
</head>

<body>
    <script>
        //声明两个promise对象
        const p1 = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('商品数据 - 1');
            }, 1000)
        });

        const p2 = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('商品数据 - 2');
                // reject('出错啦!');
            }, 1000)
        });

        // all方法,
            // 若参数对象都返回成功的状态,能正确执行并能得到参数对象中resolved的值
            // 若参数对象有返回失败状态,则all方法的返回结果就是失败的值
        var res = Promise.all([p1, p2]);

        console.log(res);

    </script>
</body>

</html>

运行结果:

image-20220220152245244

情况3-2:若参数对象有返回失败状态,则all方法的返回结果就是失败的值

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Promise.allSettled</title>
</head>

<body>
    <script>
        //声明两个promise对象
        const p1 = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('商品数据 - 1');
            }, 1000)
        });

        const p2 = new Promise((resolve, reject) => {
            setTimeout(() => {
                // resolve('商品数据 - 2');
                reject('出错啦!');
            }, 1000)
        });

        // all方法,
            // 若参数对象都返回成功的状态,能正确执行并能得到参数对象中resolved的值
            // 若参数对象有返回失败状态,则all方法的返回结果就是失败的值
        var res = Promise.all([p1, p2]);

        console.log(res);

    </script>
</body>

</html>

运行结果:

image-20220220152353486

4、可选链操作符

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

代码实现:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>可选链操作符</title>
</head>
<body>
    <script>
        // ?.
        function main(config){
            // const dbHost = config && config.db && config.db.host;
            // 上面的表达式等价于下面的表达式
            const dbHost = config?.db?.host;

            console.log(dbHost);
        }

        main({
            db: {
                host:'192.168.1.100',
                username: 'root'
            },
            cache: {
                host: '192.168.1.200',
                username:'admin'
            }
        })
    </script>
</body>
</html>

5、动态 import 导入

概述:
动态导入模块,需要用的时候才导入;

代码实现:

hello.js:

export function hello(){
  alert('Hello');
}

app.js:

// import * as m1 from "./hello.js"; // 传统静态导入
//获取元素
const btn = document.getElementById('btn');
btn.onclick = function(){
  //import方法,动态导入
  import('./hello.js').then(module => {
    module.hello();
 });
}

动态import加载.html:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>动态 import </title>
</head>

<body>
    <button id="btn">点击</button>
    <script src="./js/app.js" type="module"></script>
</body>

</html>

运行结果:

image-20220220162018801

6、BigInt

概述:
更大的整数;

代码实现:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>BigInt</title>
</head>

<body>
    <script>
        //大整形--->在整数后边加 n
        let n = 521n;
        console.log(n, typeof (n));  //521n 'bigint'

        //函数
        let n1 = 123;
        console.log(BigInt(n1));    //123n
        // console.log(BigInt(1.2));    //Uncaught RangeError: The number 1.2 cannot be converted to a BigInt because it is not an integer

        //大数值运算
        let max = Number.MAX_SAFE_INTEGER;
        console.log(max);           //9007199254740991
        console.log(max + 1);       //9007199254740992
        console.log(max + 2);       //9007199254740992

        console.log(BigInt(max))    //9007199254740991n
        console.log(BigInt(max) + BigInt(1))        //9007199254740992n
        console.log(BigInt(max) + BigInt(2))        //9007199254740993n
    </script>
</body>

</html>

7、globalThis 对象

概述:
始终指向全局对象window;

代码实现:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>globalThis</title>
</head>

<body>
    <script>
        console.log(globalThis);
    </script>
</body>

</html>

运行结果:

image-20220220163712916

posted @ 2022-02-20 16:56  努力&选择  阅读(93)  评论(0)    收藏  举报