1、什么是 ECMAScript
ECMAScript 是由 Ecma 国际通过 ECMA-262 标准化的脚本程序设计语言。
从第 6 版开始,发生了里程碑的改动,并保持着每年迭代一个版本的习惯。
ES6=2015年,ES7=2016年,ES8=2017年,ES9=2018年,ES10=2019年,ES11=2020年以此类推。
1.1 为什么要学习 ES6
 ⚫  ES6  的版本变动内容最多,具有里程碑意义  
 
 ⚫  ES6  加入许多新的语法特性,编程实现更简单、高效  
 
 ⚫  ES6  是前端发展趋势,就业必备技能 
 
 
2、ECMASript 6 新特性
2.1.let 关键字
 let  关键字用来声明变量,使用  let  声明的变量有几个特点:  
 
 1)  不允许重复声明  
 
 2)  块儿级作用域  
 
 3)  不存在变量提升  
 
 4)  不影响作用域链  
 
 应用场景:以后声明变量使用  let  就对了 
 
    <script>//声明变量let a;let b, c, d;let e = 100;let f = 521, g = 'iloveyou', h = [];//1. 变量不能重复声明//let star = '罗志祥';//let star = '小猪';//console.log("Uncaught SyntaxError: Identifier 'star' has already been declared");//2. 块儿级作用域  全局, 函数, eval//类似块级作用于的还有:if else while for {let girl = '周扬青';console.log(girl);//可以正确输出}//console.log(girl);//console.log("Uncaught ReferenceError: girl is not defined at");//3. 不存在变量提升// console.log(song);// let song = '爱唱歌';// console.log("Uncaught ReferenceError: Cannot access 'song' before initialization");//4. 不影响作用域链{let school = '清华大学';function fn() {console.log(school);}fn();}</script>2.2. const 关键字
 const  关键字用来声明常量, const  声明有以下特点: 
 
 1)  声明必须赋初始值  
 
 2)  标识符一般为大写  
 
 3)  不允许重复声明  
 
 4)  值不允许修改  
 
 5)  块儿级作用域  
 
 注意 :  对象属性修改和数组元素变化不会出发  const  错误  
 
 应用场景:声明对象类型使用  const ,非对象类型声明选择  let 
 
    <script>//声明常量const SCHOOL = '清华大学';//1. 一定要赋初始值//const A;//console.log("Uncaught SyntaxError: Missing initializer in const declaration");//2. 一般常量使用大写(潜规则)const a = 100;//3. 常量的值不能修改//SCHOOL = '北京大学';//console.log("Uncaught TypeError: Assignment to constant variable");//4. 块儿级作用域// {//     const PLAYER = '乔丹';// }// console.log(PLAYER);// console.log("Uncaught ReferenceError: PLAYER is not defined at");//5. 对于数组和对象的元素修改, 不算做对常量的修改, 不会报错const BAT = ['百度', '阿里巴巴', '腾讯'];BAT.push('字节跳动');console.log(BAT);//输出:['百度', '阿里巴巴', '腾讯', '字节跳动']</script>2.3.变量的解构赋值
 ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构赋值。 
 
 
    <script>//ES6 允许按照一定模式从数组和对象中提取值,对变量进行赋值,这被称为解构赋值。//1. 数组的结构const SCHOOL = ['清华大学', '北京大学'];let [qinghua, beida] = SCHOOL;console.log(qinghua);//输出清华大学console.log(beida);//输出北京大学//2. 对象的解构const student = {name: "小明",age: 18,like: function () {console.log("我喜欢打篮球");}}let { name, age, like } = student;console.log(name);//输出小明console.log(age);//输出18console.log(like);//输出:ƒ () {console.log("我喜欢打篮球");}like();//输出:我喜欢打篮球</script> 注意:频繁使用对象方法、数组元素,就可以使用解构赋值形式 
 
2.4.模板字符串
 模板字符串( template string )是增强版的字符串,用反引号(` )标识,特点:  
 
 1)  字符串中可以出现换行符  
 
 2)  可以使用  ${xxx}  形式输出变量 
 
    <script>// ES6 引入新的声明字符串的方式 『``』 //1. 声明let str = `这是一个字符串`;console.log(str, typeof str);//输出:这是一个字符串 string//2. 内容中可以直接出现换行符let SCHOOL = `<ul><li>清华大学</li><li>北京大学</li></ul>`;//3.变量拼接let boy = `马云`;let word = `${boy}说让天下没有难做的生意!`;console.log(word);//输出:马云说让天下没有难做的生意!</script> 注意:当遇到字符串与变量拼接的情况使用模板字符串 
  2.5.简化对象写法
 ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。 
     <script>//ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。//这样的书写更加简洁let name = '马云';let word = function () {console.log('让天下没有难做的生意');}const obj = {name,word,say() {console.log("幸福是奋斗出来的!");}}console.log(name);//输出:马云console.log(word);//输出:ƒ () { console.log('让天下没有难做的生意'); }console.log(obj);//输出:{name: '马云', word: ƒ, say: ƒ}</script> 注意:对象简写形式简化了代码,所以以后用简写就对了  
  2.6.箭头函数
 ES6  允许使用「箭头」( => )定义函数。  
  箭头函数的注意点 :  
  1)  如果形参只有一个,则小括号可以省略  
  2) 函数体如果只有一条语句,则花括号可以省略,函数的返回值为该条语句的执行结果  
  3)  箭头函数  this  指向声明时所在作用域下  this  的值  
  4)  箭头函数不能作为构造函数实例化  
  5)  不能使用  arguments 
     <script>// ES6 允许使用「箭头」(=>)定义函数。//声明一个函数let fn = (a, b) => {return a + b;}//调用函数let result = fn(3, 5);console.log(result);//输出:8//1. this 是静态的. this 始终指向函数声明时所在作用域下的 this 的值function getName() {console.log(this.name);}let getName2 = () => {console.log(this.name);}//设置 window 对象的 name 属性window.name = '清华大学';const school = {name: "北京大学"}//直接调用getName();//输出:清华大学(作用域是 window)getName2();//输出:清华大学(作用域是 window)//call 方法调用getName.call(school);//输出:北京大学getName2.call(school);//输出:清华大学(作用域是 window)//2. 不能作为构造实例化对象// let Person = (name, age) => {//     this.name = name;//     this.age = age;// }// let me = new Person('张三', 18);// console.log(me);//输出错误信息:Person is not a constructor at//3. 不能使用 arguments 变量// let fn = () => {//     console.log(arguments);// }// fn(1, 2, 3);//输出错误信息:Uncaught SyntaxError: Identifier 'fn' has already been declared//4. 箭头函数的简写//1) 省略小括号, 当形参有且只有一个的时候let add = n => {return n + n;}console.log(add(6));//输出:12//2) 省略花括号, 当代码体只有一条语句的时候, 此时 return 必须省略// 而且语句的执行结果就是函数的返回值let pow = n => n * n;console.log(pow(9));//输出:81</script>注意:箭头函数不会更改 this 指向,用来指定回调函数会非常合适
箭头函数适合与 this 无关的回调,比如:定时器、数组的方法回调 
 箭头函数不适合与 this 有关的回调有:事件回调、对象的方法 
   2.7. rest 参数
 ES6  引入  rest  参数,用于获取函数的实参,用来代替  arguments  
 <body><div>我是div1</div><div>我是div2</div><div>我是div3</div><script>// ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments// rest 参数function getUserName(...args) {console.log(args);}getUserName('刘亦菲', '关之琳', '刘雯雯');//输出:['刘亦菲', '关之琳', '刘雯雯']// rest 参数必须要放到参数最后function fn(a, b, ...args) {console.log(a);console.log(b);console.log(args);}fn(1, 2, 3, 4, 5, 6);//输出:1、2、   [3, 4, 5, 6]//1. 数组的合并const university = ["清华大学", "北京大学"];const foreign = ["哈佛大学", "牛津大学"];const concat1 = university.concat(foreign);console.log("concat1=" + concat1);//输出:concat1=清华大学,北京大学,哈佛大学,牛津大学const concat2 = [...university, ...foreign];console.log("concat2=" + concat2);//输出:concat2=清华大学,北京大学,哈佛大学,牛津大学//2. 数组的克隆const student = ["小明", "小花", "小聪"];const copy1 = [...student];console.log("copy1=" + copy1);//输出:copy1=小明,小花,小聪//3. 将伪数组转为真正的数组const divs = document.querySelectorAll('div');//注意在文档顶部有3个divconst divArr = [...divs];console.log(divArr);//输出:[div, div, div]</script></body> 注意: rest  参数适合不定个数参数函数的场景  
 2.8. spread 扩展运算符
 扩展运算符( spread )也是三个点( ... )。它好比  rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列,对数组进行解包。  
     <script>// 『...』 扩展运算符能将『数组』转换为逗号分隔的『参数序列』//声明一个数组 ...const F4 = ['刘德华', '黎明', '张学友', '郭富城'];// 声明一个函数function tianwang() {console.log(arguments);}tianwang(...F4);//输出:Arguments(4) ['刘德华', '黎明', '张学友', '郭富城', callee: ƒ, Symbol(Symbol.iterator): ƒ]</script>2.9.Symbol
 ES6  引入了一种新的原始数据类型  Symbol,表示独一无二的值。它是JavaScript  语言的第七种数据类型,是一种类似于字符串的数据类型。 
  Symbol  特点  
  1) Symbol  的值是唯一的,用来解决命名冲突的问题  
  2) Symbol  值不能与其他数据进行运算  
  3) Symbol  定义 的 对象属 性 不能 使 用  for…in 循 环遍 历 ,但 是可 以 使 用 Reflect.ownKeys  来获取对象的所有键名。 
      <script>//创建 symbollet s1 = Symbol();console.log(s1, typeof s1);//输出:Symbol() 'symbol'let s2 = Symbol("清华大学");let s3 = Symbol.for("广东省深圳市");//不能与其他数据进行运算//let result1 = s1 + 100;//console.log(result1);//输出:Uncaught TypeError: Cannot convert a Symbol value to a number//let result2 = s2 + "教授";//console.log(result2);//输出:Uncaught TypeError: Cannot convert a Symbol value to a stringlet youxi = {name: "王者荣耀",[Symbol('zhongdan')]: function () {console.log("我可以中单")},[Symbol('daye')]: function () {console.log('我可以打野');}}console.log(youxi)</script> 注 :  遇到唯一性的场景时要想到  Symbol  
 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  
  3)  工作原理 
  a)  创建一个指针对象,指向当前数据结构的起始位置  
  b)  第一次调用对象的  next  方法,指针自动指向数据结构的第一个成员  
  c)  接下来不断调用  next  方法,指针一直往后移动,直到指向最后一个成员  
  d)  每调用  next  方法返回一个包含  value  和  done  属性的对象 
  注 :  需要自定义遍历数据的时候,要想到迭代器。 
     <script>let F4 = ["刘德华", "郭富城", "黎明", "张学友"];//使用 for...of 遍历数组for (let v of F4) {console.log(v);//循环输出:刘德华、郭富城、黎明、张学友}let iterator = F4[Symbol.iterator]();//调用对象的next方法console.log(iterator.next());//输出:{value: '刘德华', done: false}console.log(iterator.next());//输出:{value: '郭富城', done: false}console.log(iterator.next());//输出:{value: '黎明', done: false}console.log(iterator.next());//输出:{value: '张学友', done: false}console.log(iterator.next());//输出:{value: undefined, done: true}//自定义遍历数据const NBA = {name: "美国篮球协会",player: ["乔丹", "麦迪", "姚明"],[Symbol.iterator]() {//索引变量let index = 0;let _this = this;return {next: function () {if (index < _this.player.length) {const result = {value: _this.player[index], done: false};//下标自增index++;return result;} else {return { value: undefined, done: true };}}};}}//遍历这个 NBA 对象for (let v of NBA) {console.log(v);//输出:乔丹、麦迪、姚明}</script>2.11. 生成器
 生成器函数是  ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。生成器其实就是一个特殊的函数。 
     <script>//生成器其实就是一个特殊的函数//异步编程  纯回调函数//函数代码的分隔符function* NBA() {yield "乔丹";yield "麦迪";yield "姚明";}let iterator = NBA();console.log(iterator.next());//输出:{value: '乔丹', done: false}console.log(iterator.next());//输出:{value: '麦迪', done: false}   console.log(iterator.next());//输出:{value: '姚明', done: false}console.log(iterator.next());//输出:{value: undefined, done: true}//遍历for (let v of NBA()) {console.log(v);//输出:乔丹、麦迪、姚明}//生成器函数参数function* university(arg) {console.log("arg=" + arg);let one = yield "清华大学";console.log("one=" + one);let two = yield "北京大学";console.log("two=" + two);let three = yield "哈佛大学";console.log("three=" + three);}//执行获取迭代器对象let iter = university("上海交大");console.log("iter.next1=" + iter.next());//next方法可以传入实参console.log("iter.next2=" + iter.next("医科大"));console.log("iter.next3=" + iter.next("中山大学"));console.log("iter.next4=" + iter.next("复旦大学"));//依次输出:/*arg=上海交大iter.next1=[object Object]one=医科大iter.next2=[object Object]two=中山大学iter.next3=[object Object]three=复旦大学iter.next4=[object Object]*///生成器函数实例//异步编程、文件操作、网络操作(ajax、Request、数据库操作)//模拟获取:用户数据、订单数据、商品数据function getUserInfo() {setTimeout(() => {let data = "用户数据";console.log(data);//调用 next 方法,并且将数据传入info.next(data);}, 1000)}function getOrderInfo() {setTimeout(() => {let data = "订单数据";console.log(data);info.next(data);}, 1000)}function getGoodsInfo() {setTimeout(() => {let data = "商品数据";console.log(data);info.next(data);}, 1000)}function* getMallInfo() {yield getUserInfo();yield getOrderInfo();yield getGoodsInfo();}//调用生成器函数let info = getMallInfo();info.next();//依次输出:用户数据、订单数据、商品数据</script>代码说明:
 1) *  的位置没有限制  
  2)  生成器函数返回的结果是迭代器对象,调用迭代器对象的  next 方法可以得到 yield  语句后的值  
  3) yield  相当于函数的暂停标记,也可以认为是函数的分隔符,每调用一次 next 方法,执行一段代码  
  4) next  方法可以传递实参,作为  yield  语句的返回值 
 2.12. Promise(重点掌握)
 Promise  是  ES6  引入的异步编程的新解决方案。语法上  Promise 是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。 
  1) Promise  构造函数 : Promise (excutor) {}  
  2) Promise.prototype.then  方法  
  3) Promise.prototype.catch  方法  
 2.12.1 Promise基本语法
    <script>// promise 基本语法//实例化 Promise 对象const promise = new Promise(function (resolve, reject) {/* 正常读取数据*/setTimeout(function () {let data = '数据库中的用户数据';resolve(data);}, 1000);/*setTimeout(function () {let err = '数据读取失败';reject(err);});*/});//调用 promise 对象的 then 方法promise.then(function (value) {console.log(value);}, function (reason) {console.error(reason);})</script>2.12.2 Promise封装AJAX
    <script>const p = new Promise((resolve, reject) => {//1. 创建对象const xhr = new XMLHttpRequest();//2. 初始化xhr.open("GET", "输入具体的 URL 地址,比如 http://www.baidu.com/");//3. 发送xhr.send();//4. 绑定事件, 处理响应结果xhr.onreadystatechange = function () {//判断if (xhr.readyState === 4) {//判断响应状态码 200-299if (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>2.12.3 Promise then方法
   <script>//创建 promise 对象const p2 = new Promise((resolve, reject) => {setTimeout(() => {resolve('用户数据');// reject('出错啦');}, 1000)});//调用 then 方法  then方法的返回结果是 Promise 对象, 对象状态由回调函数的执行结果决定//1. 如果回调函数中返回的结果是 非 promise 类型的属性, 状态为成功, 返回值为对象的成功的值// const result = p2.then(value => {//     console.log(value);//     //1. 非 promise 类型的属性//     // return 'iloveyou';//     //2. 是 promise 对象//     // return new Promise((resolve, reject)=>{//     //     // resolve('ok');//     //     reject('error');//     // });//     //3. 抛出错误//     // throw new Error('出错啦!');//     throw '出错啦!';// }, reason=>{//     console.warn(reason);// });//链式调用p2.then(value => {}).then(value => {});</script>2.12.3 Promise catch方法
    <script>const p3 = new Promise((resolve, reject) => {setTimeout(() => {//设置 p 对象的状态为失败, 并设置失败的值reject("出错啦!");}, 1000)});// p3.then(function(value){}, function(reason){//     console.error(reason);// });p3.catch(function (reason) {console.warn(reason);});</script>2.13. Set
 ES6  提供了新的数据结构  Set(集合)。它类似于数组,但成员的值都是唯一的,集合实现了  iterator  接口,所以可以使用『扩展运算符』和『 for…of…』进行遍历,集合的属性和方法:  
  1) size 返回集合的元素个数 
  2) add 增加一个新元素,返回当前集合  
  3) delete  删除元素,返回  boolean  值 
  4) has 检测集合中是否包含某个元素,返回  boolean  值 
  5) clear 清空集合,返回  undefined 
     <script>//创建一个空集合let emptySet = new Set();//创建一个非空集合let wangzhe = new Set(["射手", "法师", "打野", "上单", "辅助"]);//返回集合的元素个数console.log(wangzhe.size);//输出:5//遍历集合for (let v of wangzhe) {console.log(v);//输出:射手、法师、打野、上单、辅助}//添加新元素console.log(wangzhe.add("野怪"));//输出:Set(6) {'射手', '法师', '打野', '上单', '辅助', '野怪'}//删除元素console.log(wangzhe.delete("野怪"));//输出:true//检测是否存在某个值console.log(wangzhe.has("野怪"));//输出:false//清空集合console.log(wangzhe.clear());//输出:undefined//set 集合的去重、并、交、差集合let arr1 = ["北京", "上海", "广州", "深圳", "上海"];//数组去重let repeat = [...new Set(arr1)];console.log("repeat=" + repeat);//输出:repeat=北京,上海,广州,深圳//交集let arr2 = ["广州", "深圳", "武汉"];let intersection = [...new Set(arr1)].filter(item => new Set(arr2).has(item));console.log("intersection=" + intersection);//输出:intersection=广州,深圳//并集let union = [...new Set([...arr1, ...arr2])];console.log("union=" + union);//输出:union=北京,上海,广州,深圳,武汉//差集let diff = [...new Set(arr1)].filter(item => !(new Set(arr2).has(item)));console.log("diff=" + diff);//输出:diff=北京,上海</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>//声明一个 maplet map = new Map();//添加元素map.set("name", "马云");map.set("word", function () {console.log("让天下没有难做的生意!");});let school = {name: "浙江师范大学"};map.set(school, ["北京大学", "清华大学"]);//map集合数据长度console.log("map.size=" + map.size);//输出:map.size=3//删除console.log(map.delete("name"));//输出:true//获取map数据console.log("word=" + map.get("word"));//输出:word=function () {console.log("让天下没有难做的生意!");}console.log("school=" + map.get("school"));//输出:school=undefined//遍历for (let m of map) {console.log(m);}/*输出:['word', ƒ][{…}, Array(2)]*///清空 mapconsole.log(map.clear());//输出:undefined</script>2.15. class 类
 ES6  提供了更接近传统语言的写法,引入了  Class(类)这个概念,作为对象的模板。通过  class  关键字,可以定义类。基本上, ES6  的  class 可以看作只是一个语法糖,它的绝大部分功能, ES5  都可以做到,新的  class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。 
  知识点:  
  1) class  声明类  
  2) constructor  定义构造函数初始化  
  3) extends  继承父类  
  4) super  调用父级构造方法  
  5) static  定义静态方法和属性  
  6)  父类方法可以重写  
     <script>class Phone {//构造方法constructor(brand, price) {this.brand = brand;this.price = price;}//方法必须使用该语法,不能使用 ES5 的对象完整形式call() {console.log("我是一部手机");}}let Huawei = new Phone("华为折叠手机", 8999);console.log(Huawei);//输出:Phone {brand: '华为折叠手机', price: 8999}//class 的 get、setclass Game {get name() {console.log("游戏的名字属性被读取了");return "王者荣耀";}set name(newName) {console.log("游戏的名字属性被修改了");}}//实例化对象let play = new Game();console.log(play.name);//输出:游戏的名字属性被读取了、 王者荣耀play.name = "打野";//游戏的名字属性被修改了//类的静态成员class University {static name = "清华大学";static word() {console.log("自强不息,厚德载物");}student() {console.log("好好学习,天天向上");}}let Tom = new University();console.log("Tom.name=" + Tom.name);//输出:Tom.name=undefinedconsole.log("Tom.word=" + Tom.word);//输出:Tom.word=undefinedconsole.log("Tom.student=" + Tom.student);//输出:Tom.student=student() {console.log("好好学习,天天向上");}console.log("University.name=" + University.name);//输出:University.name=清华大学console.log("University.word=" + University.word);//输出:University.word=word() {console.log("自强不息,厚德载物");}//结论:类的静态成员只能被该类访问//类的继承class Person {constructor(age, sex) {this.age = age;this.sex = sex;}//父类的成员属性call() {console.log("我的人类共有的特征");}}//子类继承class OtherPeople extends Person {constructor(age, sex, name) {super(age, sex);this.name = name;}//唱歌sing() {console.log("我会唱歌");}codding() {console.log("我会编程");}}const XiaoMing = new OtherPeople(18, "男", "我叫小明");XiaoMing.call();//输出:我的人类共有的特征XiaoMing.sing();//输出:我会唱歌XiaoMing.codding();//输出:我会编程</script>2.16. 数值扩展
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()  用来判断一个数值是否为整数 
      <script>//1、Number.EPSILON 是 JavaScript 表示的最小精度//EPSILON 属性的值接近于 2.2204460492503130808472633361816E-16function equal(a, b) {if (Math.abs(a, b) < Number.EPSILON) {return true;} else {return false;}}console.log(1 + 2 == 3);//输出:trueconsole.log(1 + 2 === 3);//输出:trueconsole.log(0.1 + 0.2 == 0.3);//输出:falseconsole.log(0.1 + 0.2 === 0.3);//输出:falseconsole.log(equal(0.1 + 0.2, 0.3));//输出:false//2、Number.isFinite 检测一个数值是否为有限数console.log("-------------------------------------");console.log(Number.isFinite(100));//输出:trueconsole.log(Number.isFinite(100 / 0));//输出:falseconsole.log(Number.isFinite(Infinity));//输出:false//3. Number.isNaN 检测一个数值是否为 NaNconsole.log("-------------------------------------");console.log(Number.isNaN(123));//输出:falseconsole.log(Number.isNaN(NaN));//输出:true//4. Number.parseInt Number.parseFloat字符串转整数console.log("-------------------------------------");console.log(Number.parseInt('123砍三刀'));//输出:123console.log(Number.parseFloat('3.1415926圆周率'));//输出:3.1415926//5. Number.isInteger 判断一个数是否为整数console.log("-------------------------------------");console.log(Number.isInteger(666));//输出:trueconsole.log(Number.isInteger(8.88));//输出:falseconsole.log(Number.isInteger("一刀999"));//输出:false//6. Math.trunc 将数字的小数部分抹掉console.log("-------------------------------------");console.log(Math.trunc(1.25));//输出:1//7. Math.sign 判断一个数到底为正数 负数 还是零console.log("-------------------------------------");console.log(Math.sign(0));//输出:0console.log(Math.sign(12306));//输出:1console.log(Math.sign(-2.98));//输出:-1</script>2.17. 对象扩展
 ES6  新增了一些  Object  对象的方法 
  1) Object.is  比较两个值是否严格相等,与『 === 』行为基本一致( +0  与  NaN )  
  2) Object.assign  对象的合并,将源对象的所有可枚举属性,复制到目标对象  
  3) __proto__ 、 setPrototypeOf 、  setPrototypeOf  可以直接设置对象的原型  
     <script>//1. Object.is 判断两个值是否完全相等 console.log(Object.is(666, 666));//输出:trueconsole.log(Object.is(NaN, NaN));//输出:trueconsole.log(NaN === NaN);//输出:false//2. Object.assign 对象的合并const dbConfigDev = {host: 'http://127.0.0.1',port: 3306,name: 'dev',pass: 'dev',dbName: 'dev数据库',remark: "这是备注,开发环境数据库"};const dbConfigTest = {host: 'http://127.0.0.2',port: 8848,name: 'test',pass: 'test',dbName: 'test数据库',info: "请开启防火墙"}console.log(Object.assign(dbConfigDev, dbConfigTest));//输出:{host: 'http://127.0.0.2', port: 8848, name: 'test', pass: 'test', dbName: 'test数据库', info: "请开启防火墙",remark: "这是备注,开发环境数据库"}//3. Object.setPrototypeOf 设置原型对象  Object.getPrototypeofconst school = {name: '清华大学'}const cities = {xiaoqu: ['北京', '上海', '深圳']}Object.setPrototypeOf(school, cities);console.log(Object.getPrototypeOf(school));//输出:{xiaoqu: Array(3)}['北京', '上海', '深圳']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  命令用于输入其他模块提供的功能  
 第 3 章 ECMASript 7 新特性
3.1.Array.prototype.includes
 Includes  方法用来检测数组中是否包含某个元素,返回布尔类型值 
  3.2.指数操作符
在 ES7 中引入指数运算符「**」,用来实现幂运算,功能与 Math.pow 结果相同
    <script>// includes   indexOf// const mingzhu = ['西游记','红楼梦','三国演义','水浒传'];//判断// console.log(mingzhu.includes('西游记'));// console.log(mingzhu.includes('金瓶梅'));// **console.log(2 ** 10);// console.log(Math.pow(2, 10));</script>第 4 章 ECMASript 8 新特性
4.1.async 和 await
async 和 await 两种语法结合可以让异步代码像同步代码一样
4.1.1.async 函数
 1. async  函数的返回值为  promise  对象,  
  2. promise  对象的结果由  async  函数执行的返回值决定 
     <script>//async 函数async function fn(){// 返回一个字符串// return '清华大学';// 返回的结果不是一个 Promise 类型的对象, 返回的结果就是成功 Promise 对象// return;//抛出错误, 返回的结果是一个失败的 Promise// throw new Error('出错啦!');//返回的结果如果是一个 Promise 对象return new Promise((resolve, reject)=>{resolve('成功的数据');// reject("失败的错误");});}const result = fn();//调用 then 方法result.then(value => {console.log(value);}, reason => {console.warn(reason);})</script>4.1.2.await 表达式
1. await 必须写在 async 函数中
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 result = await p;//console.log(result);} catch (e) {console.log(e);}}//调用函数main();</script>4.2.Object.values 和 Object.entries
 1. Object.values() 方法返回一个给定对象的所有可枚举属性值的数组 
  2. Object.entries() 方法返回一个给定对象自身可遍历属性  [key,value]  的数组  
  4.3.Object.getOwnPropertyDescriptors
 该方法返回指定对象所有自身属性的描述对象 
  4.4 async与await封装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 测试  axiosasync 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.5 ES8 对象方法扩展
    <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>第 5 章 ECMASript 9 新特性
5.1.Rest/Spread 属性
 Rest  参数与  spread  扩展运算符在  ES6  中已经引入,不过  ES6 中只针对于数组,在  ES9  中为对象提供了像数组一样的  rest  参数和扩展运算符。 
  function connect({host, port, ...user}) {console.log(host);console.log(port);console.log(user);
}
connect({host: '127.0.0.1',port: 3306,username: 'root',password: 'root',type: 'master'
});5.2.正则表达式命名捕获组
 ES9  允许命名捕获组使用符号『 ?<name> 』 , 这样获取捕获结果可读性更强 
 let str = '<a href="http://www.baidu.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 章 ECMASript 10 新特性
 6.1.Object.fromEntries  
     <script>//二维数组// const result = Object.fromEntries([//     ['name','北京大学'],//     ['xueke', 'Java,大数据,前端,云计算']// ]);//Map// const m = new Map();// m.set('name','BEIJING');// const result = Object.fromEntries(m);//Object.entries ES8const arr = Object.entries({name: "北京大学"})console.log(arr);</script> 6.2.trimStart  和  trimEnd  
     <script>    // trimlet str = '   iloveyou   ';console.log(str);console.log(str.trimStart());console.log(str.trimEnd());</script> 6.3.Array.prototype.flat  与  flatMap  
     <script>//flat 平//将多维数组转化为低位数组// const arr = [1,2,3,4,[5,6]];// const arr = [1,2,3,4,[5,6,[7,8,9]]];//参数为深度 是一个数字// console.log(arr.flat(2));  //flatMapconst arr = [1,2,3,4];const result = arr.flatMap(item => [item * 10]);console.log(result);</script> 6.4.Symbol.prototype.description 
     <script>//创建 Symbollet s = Symbol('清华大学');console.log(s.description);</script>第 7 章 ECMASript 11 新特性
 7.1.String.prototype.matchAll  
     <script>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);// for(let v of result){//     console.log(v);// }const arr = [...result];console.log(arr);</script> 7.2. 类的私有属性  
     <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);// console.log(girl.#weight);girl.intro();</script> 7.3.Promise.allSettled  
     <script>//声明两个promise对象const p1 = new Promise((resolve, reject)=>{setTimeout(()=>{resolve('商品数据 - 1');},1000)});const p2 = new Promise((resolve, reject)=>{setTimeout(()=>{resolve('商品数据 - 2');// reject('出错啦!');},1000)});//调用 allsettled 方法// const result = Promise.allSettled([p1, p2]);// const res = Promise.all([p1, p2]);console.log(res);</script> 7.4. 可选链操作符  
     <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> 7.5. 动态  import  导入  
 <body><button id="btn">点击</button><script src="./js/app.js" type="module"></script>
</body> 7.6.globalThis  对象 
     <script>console.log(globalThis);</script>