Bootstrap

尚硅谷Web前端ES6教程详细笔记,涵盖ES6-ES11

1 ES介绍

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8s9OI9nc-1678681806011)(ES6%EF%BC%88%E5%B0%9A%E7%A1%85%E8%B0%B7%EF%BC%89%206890de40a61e43e1a9f7ea008717ab2e/Untitled.png)]

2 ES6的新特性

2.1 let关键字

2.1.1 声明变量

let a;
let b,c,d;
let e=100;
let f=521,g="iloveyou",h=[]

2.1.1 特点

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

  1. 变量不能重复声明
let star='罗志祥';
let star='小猪'  //error

//但使用var 重复定义 star 不会报错,因此要使用let,防止变量污染
  1. let有块级作用域

全局,函数,eval

{
    let girl='周扬青'
}
console.log(girl) //error

不仅仅针对花括号,例如if 、else、while、for里面

  1. 不存在变量提升
console.log(song)   //error
let song='恋爱达人'

//var可变量提升,在变量定义之前可以使用,不会报错
  1. 不影响作用域链
{
	let school='abc'
	function fn(){
	    console.log(school) //abc
	}
	fn()
}

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

2.1.3 案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div>
        <div class="item" style="width: 50px;height: 50px;background-color: red"></div>
        <div class="item" style="width: 50px;height: 50px;background-color: red"></div>
        <div class="item" style="width: 50px;height: 50px;background-color: red"></div>
    </div>
    <script>
        let items=document.getElementsByClassName("item");
        for (var i=0;i<items.length;i++){
            items[i].οnclick=function (){
                items[i].style.backgroundColor='pink';
            }
        }
        console.log(windows.i)  //3 error
        // 当var=3的时候,点击事件开始向外层作用域找,找不到,就是windows.i,此时是3,
        // 如果是let i,具有块级作用域,所以每一次触碰事件的i都是不同的。
        // 将var换成let即不会报错,功能正常
    </script>
</body>
</html>

2.2 const 特性

2.2.1 声明变量

const ABC = 'abc'

2.2.2 特点

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

  1. 一定要赋初始值
const A; //error
  1. 一般常量使用大写(潜规则)
  2. 常量的值不能修改
  3. 也具有块级作用域
{
    const pyaler = 'uzi'
}
console.log(player) //error
  1. 对于数组和对象的元素修改,不算作对常量的修改
const TEAM = ['uzi','MXLG','Ming','Letme'];
TEAM.push('Meiko'); //不报错,常量地址没有发生变化

TEAM = 100 //error

2.2.3 注意和应用场景

注意: 对象属性修改和数组元素变化不会出发 const 错误

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

2.3 变量的解构赋值

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

数组的解构(不常用)

const F4 = ['小沈阳','刘能','赵四','宋小宝']
let [xiao,liu,zhao,song] = F4; 
console.log(xiao)
console.log(liu)
console.log(zhao)
console.log(song)

对象的解构(常用)

const zhao = {
    name : '赵本山',
    age: '不详',
    xiaopin: function(){
        console.log("我可以演小品")
    }
}
let {name,age,xiaopin} = zhao;
console.log(name);
console.log(age);
console.log(xiaopin);
xiaopin();

// 不用以上方法的话,使用xiaopin方法时,需要 zhao.xiaopin()
// 使用以上方法结构,只需要 xiaopin() ,不用带前面的 zhao.

复杂结构

let wangfei = {
 name: '王菲',
 age: 18,
 songs: ['红豆', '流年', '暧昧', '传奇'],
 history: [
 {name: '窦唯'},
 {name: '李亚鹏'},
 {name: '谢霆锋'}
 ]
};
let {songs: [one, two, three], history: [first, second, third]} = 
wangfei;

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

2.4 模板字符串

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

  1. 字符串中可以出现换行符
  2. 可以使用 ${xxx} 形式输出变量
// 声明
let str = `我也是一个字符串`
console.log(str,typeof str);

// 特性1:内容中可以直接出现换行符
// 否则之前使用 ""+ 进行拼接
let str = `<ul>
					<li>沈腾</li>
					 <li>玛丽</li>
					 <li>魏翔</li>
					 <li>艾伦</li>
					 </ul>`;

// 特性2:变量拼接
let lovest = '魏翔';
let out = `${lovest}在前几年离开了开心麻花`;
console.log(out)

注意:当遇到字符串与变量拼接的情况使用模板字符串

2.5 简化对象写法

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

属性名和变量名相同的话,可以进行简化。

let name = '尚硅谷';
let slogon = '永远追求行业更高标准';
let improve = function () {
 console.log('可以提高你的技能');
}
//属性和方法简写
let atguigu = {
 name,   //name:name, 简写成 name
 slogon,  //slogon:slogon, 简写成 slogon
 improve,
 change() {
	 console.log('可以改变你')
 }
}

注意:对象简写形式简化了代码,所以以后用简写就对了

2.6 箭头函数

ES6 允许使用「箭头」(=>)定义函数。

/**
* 1. 通用写法
*/
let fn = (arg1, arg2, arg3) => {
 return arg1 + arg2 + arg3;
}
fn(1,2,3)

2.6.1 特性

  1. this是静态的,this始终指向函数声明时所在作用域下的this的值
function A(){
    console.log(this.name)
}

let B = () => {
    console.log(this.name);
}

window.name = '尚硅谷';
const school = {
    name: 'ATGUIGU'
}

//直接调用
A()   //尚硅谷
B()  //尚硅谷

//call 改变作用域
A.call(school); //ATGUIGU
B.call(school);  //尚硅谷 箭头函数的this值未改变
  1. 不能作为构造实例化对象
let A = (name,age) => {
    this.name=name;
    this.age=age;
}
let me = new A('xiao',123);
console.me //error
  1. 不能使用arguments变量

(arguments变量是用来保存实参的)

let fn = () => {
    console.log(arguments);
}
fn(1,2,3)  //error
  1. 简写
  • 省略小括号,当形参有且只有一个的时候
let add = n => {
    return n + 1;
}
  • 省略花括号,当代码体只有一条语句的时候,此时return也必须省略
let add = n => n+1;

注意:箭头函数不会更改 this 指向,用来指定回调函数会非常合适

2.6.2 实战

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <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');
				// 绑定事件
        // 方法1: 
        ad.addEventListener("click", function(){
            //保存 this 的值
            let _this = this; //将外层的this值进行保存,下面函数里面就可以用了,
															//	否则下面函数的this不同,并没有包含style属性,就会报错
            //定时器
            setTimeout(function(){
                //修改背景颜色 this
                // console.log(this);  
                _this.style.background = 'pink';
            }, 2000);
        });
			 // 方法2: 使用箭头函数,因为箭头函数是静态的,始终指向创建时的this值 
        ad.addEventListener("click", function(){
            setTimeout(() => {
                //修改背景颜色 this
                this.style.background = 'pink';
            }, 2000);
        });

        //需求-2  从数组中返回偶数的元素
        const arr = [1,6,9,10,100,25];
				//方法1:
        // const result = arr.filter(function(item){
        //     if(item % 2 === 0){
        //         return true;
        //     }else{
        //         return false;
        //     }
        // });
        
				// 方法2: 使用箭头函数
        const result = arr.filter(item => item % 2 === 0);
        console.log(result);

        // 箭头函数适合与 this 无关的回调. 定时器, 数组的方法回调
        // 箭头函数不适合与 this 有关的回调.  事件回调, 对象的方法

    </script>
</body>

</html>

2.6.3 函数参数默认值

  1. 可以给形参赋初始值,一般位置要靠后(潜规则)
function add(a,b,c=12){
    return a+b+c; 
}
let result = add (1,2);
console.log(result) // 15
  1. 与解构赋值结合
function A({host='127.0.0.1',username,password,port}){
    console.log(host+username+password+port)
}
A({
		host:"shangguigu.com",
    username:'ran',
    password:'123456',
    port:3306
})
// 传参了,使用传的值,没传参使用默认值

2.7 rest 参数

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

/**
* 作用与 arguments 类似
*/
function add(...args){
 console.log(args);  
}
add(1,2,3,4,5);  //得到的是一个数组,可以使用数字的一些方法:filter、some、every、map
/**
* rest 参数必须是最后一个形参
*/
function minus(a,b,...args){
 console.log(a,b,args);
}
minus(100,1,2,3,4,5,19);

注意:rest 参数非常适合不定个数参数函数的场景

2.8 spread 扩展运算符

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

特性

const tfboys=['AA','BB','CC']
function chunwan(){
    console.log(arguments);
}
chunwan(...tfboys);  //0:'AA' 1:'BB' 2:'CC'

rest 参数 和 spread区别:

rest 参数 : function add(…args) 是放在函数传参

spread: fn(…tfboys) 是放在调用函数时

应用

  1. 数组的合并
const A = ['aa','bb'];
const B = ['cc','dd'];

//方法1:
const C = A.concat(B)
console.log(C)   //[aa,bb,cc,dd]

//方法2:(推荐)
const C = [...A,...B];
console.log(C)   //[aa,bb,cc,dd]
  1. 数组的克隆(浅拷贝)
const A = ['a','b','c'];
const B = [...A];
console.log(B)   //[a,b,c]
  1. 将伪数组转换为真正的数组
const A = documents.querySelectorAll('div');
const B = [...A];
console.log(B) // [div,div,div]

2.9 Symbol

2.9.1 Symbol 基本使用

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

Symbol 特点:

  1. Symbol 的值是唯一的,用来解决命名冲突的问题
  2. Symbol 值不能与其他数据进行运算
  3. Symbol 定义 的 对象属 性 不能 使 用 for…in 循 环遍 历 ,但 是可 以 使 用
    Reflect.ownKeys 来获取对象的所有键名
// 1. 创建
//创建 Symbol
let s1 = Symbol();
console.log(s1, typeof s1);  //内部实现唯一性,我们看不到

//添加标识的 Symbol
let s2 = Symbol('尚硅谷');
let s2_2 = Symbol('尚硅谷');
console.log(s2 === s2_2);  //false

//使用 Symbol for 定义
let s3 = Symbol.for('尚硅谷');
let s3_2 = Symbol.for('尚硅谷');
console.log(s3 === s3_2);  //true

// 2. 不能与其他数据进行运算
let result = s + 100  //error
let result = s > 100  //error
let result = s + s  //error
	// 数据类型
	// USONB you are so niubility
	u undefined
	s string symbol
	o object
	n bull number
	b boolean

// 3.Symbol内置值
class Person {
    static [Symbol.hasInstance](param){
        console.log(param);
        console.log("我被用来检测了");
        return false;
    }
}
let o = {};
console.log(o instanceof Person); //我被用来检测了,false

注: 遇到唯一性的场景时要想到 Symbol

2.9.2 应用

  1. 给对象添加方法方式一:
let game = {
    name : 'ran'
}
let methods = {
    up:Symbol()
    down:Symbol()
}
game[methods.up]=function(){
    console.log('aaa');
}
game[methods.down]=function(){
    console.log('bbb');
}
console.log(game)    // name: 'ran',Symbol(),Symbol()
  1. 给对象添加方法方式二
let youxi = {
    name: '狼人杀',
    [Symbol('say')]:function(){
        console.log('阿萨德')
    }
}
console.log(youxi)    // name:'狼人杀',Symbol(say)

2.9.3 Symbol 内置值

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SnolV3LY-1678681806012)(ES6%EF%BC%88%E5%B0%9A%E7%A1%85%E8%B0%B7%EF%BC%89%206890de40a61e43e1a9f7ea008717ab2e/Untitled%201.png)]

2.10 迭代器

    迭代器(Iterator)就是一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。
  1. ES6 创造了一种新的遍历命令 for…of 循环,Iterator 接口主要供 for…of 消费

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

a) Array

b) Arguments

c) Set

d) Map

e) String

f) TypedArray

g) NodeList

  1. 工作原理

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

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

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

d) 每调用 next 方法返回一个包含 value 和 done 属性的对象

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

const xiyou=['AA','BB','CC','DD'];
//for in保存的是键名,for of保存的是键值
// for(let v of xiyou){
//     console.log(v)  // 'AA','BB','CC','DD'  
// }
let iterator = xiyou[Symbol.iterator]();
console.log(iterator.next()); //{{value:'唐僧',done:false}}
console.log(iterator.next()); //{{value:'孙悟空',done:false}}
const banji = {
    name : "终极一班",
    stus: [
        'aa',
        'bb',
        'cc',
        'dd'
    ],
    [Symbol.iterator](){
        let index = 0;
        let _this = this;
        return {
            next: () => {
                if(index < this.stus.length){
                    const result = {value: _this.stus[index],done: false};
                    //下标自增
                    index++;
                    //返回结果
                    return result;
                }else {
                    return {value: underfined,done:true};
                }
            }
        }
    }
}
for(let v of banji){
    console.log(v);  // aa bb cc dd
}

2.11 生成器

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

// 生成器其实就是一个特殊的函数
//异步编程 纯回调函数 node 方式 ajax mongodb

function * gen (){    //函数名和function中间有一个 * 
    yield '耳朵';     //yield是函数代码的分隔符
    yield '尾巴';
    yield '真奇怪';
}
let iterator = gen();
console.log(iteretor.next()); 
//{value:'耳朵',done:false} next()执行第一段,并且返回yield后面的值
console.log(iteretor.next()); //{value:'尾巴',done:false}
console.log(iteretor.next()); //{value:'真奇怪',done:false}

代码说明:

  1. *的位置没有限制
  2. 生成器函数返回的结果是迭代器对象,调用迭代器对象的 next 方法可以得到
    yield 语句后的值
  3. yield 相当于函数的暂停标记,也可以认为是函数的分隔符,每调用一次 next
    方法,执行一段代码
  4. next 方法可以传递实参,作为 yield 语句的返回值

2.11.1 应用

  1. 生成器函数的参数传递
function * gen(args){
    console.log(args);
    let one = yield 111;
    console.log(one);
    let two = yield 222;
    console.log(two);
    let three = yield 333;
    console.log(three);
}

let iterator = gen('AAA');
console.log(iterator.next());
console.log(iterator.next('BBB'));  //next中传入的BBB将作为yield 111的返回结果
console.log(iterator.next('CCC'));  //next中传入的CCC将作为yield 222的返回结果
console.log(iterator.next('DDD'));  //next中传入的DDD将作为yield 333的返回结果
  1. 实例1:用生成器函数的方式解决回调地狱问题
function one(){
    setTimeout(()=>{
        console.log('111')
        iterator.next()
    },1000)
}
function two(){
    setTimeout(()=>{
        console.log('222')
        iterator.next();
    },2000)
}
function three(){
    setTimeout(()=>{
        console.log('333')
        iterator.next();
    },3000)
}

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

let iterator = gen();
iterator.next();
  1. 实例2:模拟异步获取数据
function one(){
    setTimeout(()=>{
        let data='用户数据';
        iterator.next(data)
    },1000)
}
function two(){
    setTimeout(()=>{
        let data='订单数据';
        iterator.next(data)
    },2000)
}
function three(){
    setTimeout(()=>{
        let data='商品数据';
        iterator.next(data)
    },3000)
}

function * gen(){
    let users=yield one();
    console.log(users)
    let orders=yield two();
    console.log(orders)
    let goods=yield three();
    console.log(goods)
}

let iterator = gen();
iterator.next();

2.12 Promise

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

Promise的三种状态:初始化,成功,失败

  1. Promise 构造函数(基本用法)
<script>
    const p =new Promise((resolve, reject)=>{
        setTimeout(()=>{
            let data='数据库数据'
            // resolve(data);  //调用成功
            reject(data);   //调用失败
        },1000)
    })

    p.then(function (value){         //成功则执行第一个回调函数,失败则执行第二个
        console.log(value)
    },function (reason){
        console.error(reason)
    })
</script>
  1. promise读取文件
//1. 引入 fs 模块
const fs = require('fs');

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

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

p.then(function(value){
    console.log(value.toString());
}, function(reason){
    console.log("读取失败!!");
});
  1. 发送 AJAX 请求
<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");

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

        //4. 绑定事件, 处理响应结果
        xhr.onreadystatechange = function () {
            //判断
            if (xhr.readyState === 4) {
                //判断响应状态码 200-299
                if (xhr.status >= 200 && xhr.status < 300) {
                    //表示成功
                    resolve(xhr.response);
                } else {
                    //如果失败
                    reject(xhr.status);
                }
            }
        }
    })
    
    //指定回调
    p.then(function(value){
        console.log(value);
    }, function(reason){
        console.error(reason);
    });
</script>
  1. Promise.prototype.then 方法
<script>
  //创建 promise 对象
  const p = new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('用户数据');
      // reject('出错啦');
    }, 1000)
  });

  // 调用 then 方法  then方法的返回结果是 Promise 对象, 对象状态由回调函数的执行结果决定
  // 1. 如果回调函数中返回的结果是 非 promise 类型的属性, 状态为成功, 返回值为对象的成功的值

  const result = p.then(value => {
    console.log(value);
    //1. 非 promise 类型的属性
    return 'iloveyou';
    //2. 是 promise 对象
    // 内部返回的promise对象的状态决定then返回的promise状态
    return new Promise((resolve, reject) => {
      // resolve('ok');  
      reject('error');
    });
    //3. 抛出错误,状态为 rejected,值为throw抛出的值
    // throw new Error('出错啦!');
    throw '出错啦!';
  }, reason => {
    console.warn(reason);
  });

  //链式调用,可以杜绝回调地狱的问题
  p.then(value => {

  }).then(value => {

  });

</script>
  1. Promise.prototype.catch 方法
//catch()函数只有一个回调函数,意味着如果Promise对象状态为失败就会调用catch()方法并且调用回调函数
<script>
    const p = new Promise((resolve, reject)=>{
        setTimeout(()=>{
            //设置 p 对象的状态为失败, 并设置失败的值
            reject("出错啦!");
        }, 1000)
    });

		// 方法1:
    // p.then(function(value){}, function(reason){
    //     console.error(reason);
    // });

		// 方法2:(语法糖)
    p.catch(function(reason){
        console.warn(reason);
    });
</script>
  1. 应用:读取多个文件
//引入 fs 模块
const fs = require("fs");

// fs.readFile('./resources/为学.md', (err, data1)=>{
//     fs.readFile('./resources/插秧诗.md', (err, data2)=>{
//         fs.readFile('./resources/观书有感.md', (err, data3)=>{
//             let result = data1 + '\r\n' +data2  +'\r\n'+ data3;
//             console.log(result);
//         });
//     });
// });

//使用 promise 实现
const p = new Promise((resolve, reject) => {
    fs.readFile("./resources/为学.md", (err, data) => {
        resolve(data);
    });
});

p.then(value => {
    return new Promise((resolve, reject) => {
        fs.readFile("./resources/插秧诗.md", (err, data) => {
            resolve([value, data]);
        });
    });
}).then(value => {
    return new Promise((resolve, reject) => {
        fs.readFile("./resources/观书有感.md", (err, data) => {
            //压入
            value.push(data);
            resolve(value);
        });
    })
}).then(value => {
    console.log(value.join('\r\n'));
});

2.13 Set

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

  1. size 返回集合的元素个数
  2. add 增加一个新元素,返回当前集合
  3. delete 删除元素,返回 boolean 值
  4. has 检测集合中是否包含某个元素,返回 boolean 值
  5. clear 清空集合,返回 undefined
<script>
		//创建一个空集合
    let s = new Set();
		//创建一个非空集合
    let s2 = new Set(['A','B','C','D'])

    //元素个数
    console.log(s2.size);

    //添加新的元素
    s2.add('E');

    //删除元素
    s2.delete('A')

    //检测是否存在某个值,有true,没有false
    console.log(s2.has('C'));

    //清空集合
    s2.clear()
		
    console.log(s2);

		for(let v of s2){
        console.log(v);
    }
</script>
//应用
<script>
  let arr = [1,2,3,4,5,4,3,2,1]

  //1.数组去重
  let result = [...new Set(arr)]
  console.log(result);
  //2.交集
  let arr2=[4,5,6,5,6]
  let result2 = [...new Set(arr)].filter(item => new Set(arr2).has(item))
  console.log(result2);
  //3.并集
  let result3=[...new Set([...arr,...arr2])]
  console.log(result3);
  //4.差集 是交集的取反
  let result4= [...new Set(arr)].filter(item => !(new Set(arr2).has(item)))
  console.log(result4);

</script>

2.14 Map

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

  1. size 返回 Map 的元素个数
  2. set 增加一个新元素,返回当前 Map
  3. get 返回键名对象的键值
  4. has 检测 Map 中是否包含某个元素,返回 boolean 值
  5. clear 清空集合,返回 undefined
<script>
		//创建一个空 map
    let m = new Map();

		//添加元素 第一个参数是键,第二个参数是值
    m.set('name','ran');
    m.set('change',()=>{
        console.log('改变!')
    })
    let key={
        school:'atguigu'
    }
    m.set(key,['北京','西安']);

    //size 长度
    console.log(m.size);

    //删除
    m.delete('name');

    //获取
    console.log(m.get('change'));

		//检测是否有该映射
		console.log(m2.has('age'));

    // 清空
    // m.clear()

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

2.15 class 类

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

  1. class 声明类
  2. constructor 定义构造函数初始化
  3. extends 继承父类
  4. super 调用父级构造方法
  5. static 定义静态方法和属性
  6. 父类方法可以重写
//父类
class Phone {
 //构造方法
 // constructor 这个名字不能修改,在进行new Phone时,自动执行
 constructor(brand, color, price) {
	 this.brand = brand;
	 this.color = color;
	 this.price = price;
 }
 //对象方法,只能使用 方法名(){} 的写法,不能使用 方法名:function(){}
 call() {
			console.log('我可以打电话!!!')
	 }
	}

	//子类
	class SmartPhone extends Phone {
	 constructor(brand, color, price, screen, pixel) {
		 super(brand, color, price);
		 this.screen = screen;
		 this.pixel = pixel;
	 }
	 //子类方法
	 photo(){
		 console.log('我可以拍照!!');
	 }
	 playGame(){
		 console.log('我可以玩游戏!!');
	 }
	 //方法重写
	 call(){
		 console.log('我可以进行视频通话!!');
	 }
	 //静态方法
	 static run(){
		 console.log('我可以运行程序')
	 }
	 static connect(){
		 console.log('我可以建立连接')
	 }
	}
//实例化对象
const Nokia = new Phone('诺基亚', '灰色', 230);
const iPhone6s = new SmartPhone('苹果', '白色', 6088, 
'4.7inch','500w');
//调用子类方法
iPhone6s.playGame();
//调用重写方法
iPhone6s.call();
//调用静态方法
SmartPhone.run();

2.15.1 特性

<script>
	//=================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 这个名字不能修改,在进行new Phone时,自动执行
      constructor(brand,price) {
          this.brand=brand;
          this.price=price
      }

		//对象方法,只能使用 方法名(){} 的写法,不能使用 方法名:function(){}
      call(){
          console.log('我可以打电话')
      }
  }

  let A = new shouji('1+',1999);
  console.log(A)
</script>

2.15.2 静态成员

<script>
		//=================ES5========================
    // function Phone(){

    // }
    // Phone.name = '手机';

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

    // let nokia = new Phone();

    // console.log(nokia.name);
    // // nokia.change();  //访问不到change方法,原因:只能访问到原型链上的方法
    // console.log(nokia.size);

		//=================ES6========================
    class Phone{
        //静态属性
        static name = '手机';
        static change(){
            console.log("我可以改变世界");
        }
    }

    let nokia = new Phone();
    console.log(nokia.name);  // 都可以访问到
    console.log(Phone.name);
</script>

2.15.3 继承

ES5构造函数继承

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

  //设置子级构造函数原型
  SmartPhone.prototype=new Phone;
  SmartPhone.prototype.constructor=SmartPhone; //做一个矫正,这行不加也可以

  //声明子类方法
  SmartPhone.prototype.photo = function (){
      console.log('我可以拍照');
  }
  const chuizi = new SmartPhone('锤子',2499,'黑色','5.5inch')
  console.log(chuizi);
</script>

Class的类继承

<script>
//=================ES6========================
  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); // 等价于ES5中的Phone.call(this,brand,price);
          this.color=color;
          this.size=size;
      }
      photo(){
          console.log('拍照');
      }

      playGame(){
          console.log('打游戏');
      }
  }
  const xiaomi=new SmartPhone('小米',1999,'黑色','4.7inch')
  xiaomi.call();
  xiaomi.photo();
  xiaomi.playGame();
</script>

2.15.4 子类对父类方法的重写

<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);
            this.color=color;
            this.size=size;
        }
        photo(){
            console.log('拍照');
        }

        playGame(){
            console.log('打游戏');
        }

        //重写!
        call(){
            console.log('我可以进行视频通话')
        }
    }
    const xiaomi=new SmartPhone('小米',1999,'黑色','4.7inch')
    xiaomi.call();
    xiaomi.photo();
    xiaomi.playGame();
</script>

2.15.5 get和set设置

<script>
  class Phone{
      get price(){
          console.log("价格被读取了")
          return 'I LOVE YOU'
      }

			// 注意:set需要传参,否则会报错
      set price(val){
          console.log('价格被修改了')
          return val;
      }
  }

    //实例化对象
    let s = new Phone();
    s.price=12  
    // console.log(s.price)   //其实是调用price方法
</script>

2.16 数值扩展

<script>
 // 1.Number.EPSILON
 // Number.EPSILON 是 JavaScript的最小精度,属性的值接近于 2.22044...E-16
 // 判断两个值如果小于 Number.EPSILON 则认为 这两个值相等
 // 主要用于浮点数
	function equal(a,b){
       if(Math.abs(a-b) < Number.EPSILON){
           return true;
       }else {
           return false;
       }
   }
   console.log(equal(0.1 + 0.2 === 0.3))  //false
   console.log(equal(0.1+0.2,0.3))  //true

   //2. 二进制和八进制
   let b = 0b1010; //2进制
   let o = 0o777;  //8进制
   let d = 100;    //10进制
   let x = 0xff;   //16进制
   console.log(x)   //255

   //3. Number.isFinite 检测一个数是否为有限数
   console.log(Number.isFinite(100));  //true
   console.log(Number.isFinite(100/0));  //false
   console.log(Number.isFinite(Infinity));  //false

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

   //5. 字符串转整数
   console.log(Number.parseInt('5213123love')); //5213123
   console.log(Number.parseFloat('5.123123神器')); //5.123123

   //6. 判断是否为整数
   console.log(Number.isInteger(5));  //true
   console.log(Number.isInteger(2.5)); //false
   
   //7. 将小数部分抹除
   console.log(Math.trunc(3.45345345345)) //3

   //8. 检测一个数到底是正数、负数、还是0
   console.log(Math.sign(100)) //1
   console.log(Math.sign(0))  //0
   console.log(Math.sign(-123)) //-1
</script>

2.16.1 二进制和八进制

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

2.16.2 Number.isFinite() 与 Number.isNaN()

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

2.16.3 Number.parseInt() 与 Number.parseFloat()

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

2.16.4 Math.trunc

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

2.16.5 Number.isInteger

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

2.17 对象扩展

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

  1. Object.is 比较两个值是否严格相等,与『===』行为基本一致(+0 与 NaN)
  2. Object.assign 对象的合并,将源对象的所有可枚举属性,复制到目标对象
  3. proto、setPrototypeOf、 setPrototypeOf 可以直接设置对象的原型
<script>
    //1.Object.is 判断两个值是否完全相等
		// 跟全等号=== 类似,区别在于:全等号NaN === NaN 是false
    console.log(Object.is(120,120))  //true
		console.log(Object.is(NaN,NaN))  //true

    //2.Object.assign 对象的合并
   const config1 = {
        host: 'localhost',
        port: 3306,
        name: 'root',
        pass: 'root',
        test: 'test'
    };
    const config2 = {
        host: 'http://atguigu.com',
        port: 33060,
        name: 'atguigu.com',
        pass: 'iloveyou',
        test2: 'test2'
    }
        
		//将b合并到a
		// 如果a,b里面都有的元素,b会覆盖a中的元素
		// 如果a里面有,b里面没有的,保留;其他有的元素覆盖a的
		// 如果b里面有,a里面没有的,保留;其他有的元素覆盖a的
		console.log(Object.assign(config1, config2));
    

    //3.Object.setPrototypeOf 设置原型对象 Object.getPrototypeof(不建议)
		//建议在创建对象的时候就创建原型
    const school = {
        name:'尚硅谷'
    }
    const cities = {
        xiaoqu:['北京','上海']
    }
    Object.setPrototypeOf(school,cities)   //设置原型
    console.log(Object.getPrototypeOf(school))  //获取原型 {xiaoqu: Array(2)}
    console.log(school)  //{name: "尚硅谷"}
</script>

2.18 模块化

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

2.18.1 模块化的好处

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

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

2.18.2 模块化规范产品

ES6 之前的模块化规范有:

  1. CommonJS => NodeJS、Browserify
  2. AMD => requireJS
  3. CMD => seaJS

2.18.3 ES6 模块化语法

模块功能主要由两个命令构成:export 和 import。

  • export 命令用于规定模块的对外接口
  • import 命令用于输入其他模块提供的功能

导出语法汇总

  1. 分别暴露
// m1.js
export let school = '尚硅谷'
export function teach(){
    console.log('教技能')
}
// index.html
<script type="module">
    import * as m1 from "./src/js/m1.js";
	  console.log(m1);
</script>
  1. 统一暴露
// m2.js
//统一暴露
let school = '尚硅谷';
function findjob(){
    console.log('找工作吧');
}
export {school,findjob}
// index.html
<script type="module">
    import * as m2 from "./src/js/m2.js";
	  console.log(m2);
</script>
  1. 默认暴露
//m3.js
//默认暴露
export default {
    school:'ATGUIGU',
    change:function(){
        console.log('我们可以改变你')
    }
}
// index.html
<script type="module">
    import * as m3 from "./src/js/m3.js";
	  console.log(m3);
</script>

引入语法汇总

  1. 通用导入方式
import * as m1 from "./src/js/m1.js"
import * as m2 from "./src/js/m2.js"
import * as m3 from "./src/js/m3.js"
  1. 解构赋值方式
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"   // 必须给default起个别名
  1. 简便形式(只针对默认暴露)

    只能针对默认暴露

import m3 from "./src/js/m3.js"

2.18.6 模块化方式2

// app.js
import * as m1 from "./src/js/m1.js"
import * as m2 from "./src/js/m2.js"
import * as m3 from "./src/js/m3.js"
//index.html  

//不推荐 原因:浏览器的兼容问题
<script src="./src/js/app.js" type=modeule></script>

// 推荐 把es6转化为es5的语法
<!-- 
  1. 安装工具 npm i babel-cli babel-preset-env browserify(webpack)(二选一) -D
  2. 编译 npx babel src/js -d dist/js(要保存的文件夹) --presets=babel-preset-env
  3. 打包 npx browserify dist/js/app.js(输入的文件) -o dist/bundle.js(输出的位置)
-->
<script src="dist/bundle.js"></script>

3 ES7 新特性

3.1 Array.prototype.includes

Includes 方法用来检测数组中是否包含某个元素,返回布尔类型值

<script>
    //include 比 indexOf方便,indexOf如果是没有值返回的是-1
   const mingzhu = ['西游记','红楼梦','水浒传','三国演义']
   console.log(mingzhu.includes('西游记'))  //true
   console.log(mingzhu.includes('金瓶梅'))  //false
</script>

3.2 指数操作符

在 ES7 中引入指数运算符「**」,用来实现幂运算,功能与 Math.pow 结果相同

<script>
    //** 幂运算
    console.log(2**10) // 1024
		console.log(Math.pow(2,10)) //1024
</script>

4 ES8 新特性

4.1 async 和 await

async 和 await 两种语法结合可以让异步代码像同步代码一样

4.1.1 async 函数

  1. async 函数的返回值为 promise 对象,
  2. promise 对象的结果由 async 函数执行的返回值决定
async function fn(){
   //1.如果返回的是一个非Promise的对象,则fn()返回的结果就是成功状态的Promise对象,值为返回值
		return "尚硅谷";
		return ;   

	//2.如果返回的是一个Promise对象,则fn()返回的结果与内部Promise对象的结果一致
  throw new Error("出错了")
	 
	//3.如果返回的是抛出错误,则fn()返回的就是失败状态的Promise对象
   return new Promise((resolve,reject)=>{
       resolve('成功的数据');
			 // reject("失败的错误")
   });
}
const result = fn();
result.then(value=>{
   console.log(value)  //成功的数据
},reason=>{
   console.log(reason)
})

4.1.2 await 表达式

  1. await 必须写在 async 函数中,async里面可以没有await
  2. await 右侧的表达式一般为 promise 对象
  3. await 返回的是 promise 成功的值
  4. await 的 promise 失败了, 就会抛出异常, 需要通过 try…catch 捕获处理
<script>
    //创建Promise对象
    const p = new Promise((resolve, reject) => {
        // resolve("成功的值")
        reject("失败了")
    })

    //await 必须放在async函数中
    async function main() {
        try {
            let res = await p;
            console.log(res);
        } catch (e) {
            console.log(e);
        }
    }

    //调用函数
    main()  //失败了
</script>

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(){
    //获取为学内容
    let weixue = await readWeiXue();
    //获取插秧诗内容
    let chayang = await readChaYangShi();
    // 获取观书有感
    let guanshu = await readGuanShu();

    console.log(weixue.toString());
    console.log(chayang.toString());
    console.log(guanshu.toString());
}

main();

发送AJAX请求

<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 测试  axios
    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>

4.2 Object.values 和 Object.entries

  1. Object.values()方法返回一个给定对象的所有可枚举属性值的数组
  2. Object.entries()方法返回一个给定对象自身可遍历属性 [key,value] 的数组

4.3 Object.getOwnPropertyDescriptors

该方法返回指定对象所有自身属性的描述对象

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

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

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

    //entries,用来创建map
    console.log(Object.entries(school));
    console.log(new Map(Object.entries(school)))

    //对象属性的描述对象,即获取name的值
		//主要用于拷贝时,拷贝一份与原来对象相同属性的对象
    console.log(Object.getOwnPropertyDescriptor(school))
    
    const obj = Object.create(null,{
        name:{
            value:'尚硅谷',
            //属性特性
            writable:true,  // 是否可写
            configurable:true,  //是否可配置
            enumerable:true,  //是否可枚举
        }
    })
</script>

5 ES9 新特性

5.1 Rest/Spread 属性

Rest 参数与 spread 扩展运算符在 ES6 中已经引入,不过 ES6 中只针对于数组,

在 ES9 中为对象提供了像数组一样的 rest 参数和扩展运算符

<script>
    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'
    })  //127.0.0.1  3306  {username: "root", password: "root", type: "master"}

</script>
<script>
    const AA={
        username:'ran'
    }
    const BB={
        password:'lyyrhf'
    }
    const CC={
        job:'Java'
    }
    const D={...AA,...BB,...CC};
    console.log(D) //{username: "ran", password: "lyyrhf", job: "Java"}
</script>

5.2 正则表达式命名捕获组

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

let str = '<a href="http://www.atguigu.com">尚硅谷</a>';
const reg = /<a href="(?<url>.*)">(?<text>.*)<\/a>/;
const result = reg.exec(str);
console.log(result.groups.url);
console.log(result.groups.text);

5.3 正则表达式反向断言

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

//声明字符串
let str = 'JS5211314 你知道么 555 啦啦啦';
//正向断言
const reg = /\d+(?=啦)/;
const result = reg.exec(str);
//反向断言
const reg = /(?<=么)\d+/;
const result = reg.exec(str);
console.log(result);

5.4 正则表达式 dotAll 模式

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

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

6 ES10 新特性

6.1 对象扩展方法 Object.fromEntries

用来创建一个对象,参数是一个数组或者是map对象。

将二维数组转为对象,而ES8 中 Object.entries 方法是把对象转化为数组

<script>
   //二维数组
   const res = Object.fromEntries([
       ['name','尚硅谷'],
       ['cities','成都','武汉']
   ])
   console.log(res) //{name: "尚硅谷", cities: "成都"}

   //Map
   const m = new Map();
   m.set('name','ranhaifeng')
   const result = Object.fromEntries(m)
   console.log(result); //{name: "ranhaifeng"}
</script>

6.2 字符串扩展方法 trimStart 和 trimEnd

**trimStart :**清除字符串左侧的字符

**trimEnd:**清除字符串右侧的字符

<script>
   //trim
   let str= ' asd  '
   console.log(str) //asd
   console.log(str.trimStart()) //asd  清空头空格
   console.log(str.trimEnd()) //  asd  清空尾空格
</script>

6.3 flat与flatMap

**flat:**将多维数组转化为低维数组

**flatMap:**将map对象进行降维

<script>
    const arr = [1,2,3,[4,5,6,[7,8,9]]]
    //参数为深度,是一个数字,2表示2层
    console.log(arr.flat(2)) //[1,2,3,4,5,6,7,8,9]

	const arr2=[1,2,3,4]
    const result = arr2.flatmap(item => [item * 10]); //如果map的结果是一个多维数组可以进行flat 是两个操作的结合
	
</script>

6.4 Symbol.prototype.description

用来获取Symbol的字符串描述

let s = Symbol('尚硅谷');
console.log(s.description) //尚硅谷

7 ES11 新特性

7.1 私有属性

<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.#age) //error 原因:类的外部没法得到私有属性的值,只能在类里面访问
    console.log(girl); //Person{name: "陈", #age: 18, #weight: "45kg"}

    girl.intro(); // 陈 18  45kg
</script>

7.2 Promise

allSettled 和all 方法,主要用于批量处理异步任务。

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

    const p2 = new Promise((resolve, reject) => {
        setTimeout(()=>{
            reject('出错了!')
        },1000)
    })

    //调用allsettled方法:返回的结果始终是一个成功的,并且异步任务的结果和状态都存在
    const res = Promise.allSettled([p1,p2]);
    console.log(res)

    // Promise {<pending>}
    //     __proto__: Promise
    //     [[PromiseState]]: "resolve"
    //     [[PromiseResult]]: Array(2)
		//			0: {status: 'fulfilled', value: '商品数据-1'}
		//			1: {status: 'rejected', reason: '出错了!'}

		//=========================================================
    //调用all方法:返回的结果是按照p1、p2的状态来的,
		//如果都成功,则成功,
		//如果一个失败,则失败,失败的结果是失败的Promise的结果
    const result = Promise.all([p1,p2])
    console.log(result)

</script>

7.3 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); //返回的是一个可迭代对象

	//展开可迭代对象  方法1
  // for(let v of result){
  //     console.log(v);
  // }

	//展开可迭代对象  方法2
  const arr = [...result];

  console.log(arr);

7.4 可选链操作符 ?.

免去层层判断的麻烦

//相当于一个判断符,如果前面的有,就进入下一层级
function main(config){
    const dbHost = config?.db?.host  //等价于 config && config.db && config.db.host
    console.log(dbHost) //192.168.1.100
}

main({
    db:{
        host:'192.168.1.100',
        username:'root'
    },
    cache:{
    	host:'192.168.1.200',
    	username:'admin'
	}
})

7.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(){
		//使用之前并未引入,动态引入,返回的其实是一个Promise对象
		// 使用的时候再进行传入,import函数,参数是路径
    import('./hello.js').then(module => {
        module.hello();
    });
}
// index.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>

7.6 BigInt类型

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

//函数 将整型转为大整型
let n = 123;
console.log(BigInt(n)) // 123n  //不要使用浮点型,只能用int

//大数值运算
let max = Number.MAX_SAFE_INTEGER; // 9007199254740991
console.log(max +1) // 9007199254740992
console.log(max +2) // 9007199254740992 出问题了
console.log(BigInt(max)+BigInt(1)) 9007199254740992n
console.log(BigInt(max)+BigInt(2)) 9007199254740993n

7.7 绝对全局对象globalThis

始终指向全局对象

console.log(globalThis) //window  //适用于复杂环境下直接操作window
;