ES6(第三版)知识点及各个版本总结

一、ES6与ECMAScript2015关系
ES:是编写js的标准,它规定了语法、语句、类型、关键字、保留字、操作符、对象等(js的国际标准)
JS:JavaScript 1995诞生的目的是解决以前依赖服务器语言验证用户的输入验证操作。后期发展为一门编程语言。js包含:ECMAScript标准、DOM(DOM 把整个页面映射为一个多层节点结构,dom节点树,通过dom提供的 API,开发人员可以轻松自如地删除、添加、替换或修改任何节点)、BOM(浏览器对象模型)
ES6第三版:ES2015、ES2016、ES2017版本迭代

二、let和const命令(es5用var来声明变量或function来声明函数,且es5只存在全局和函数作用域。es6增加声明变量的方法后存在块级作用域和暂时性死区)
1、let
1)let声明的变量只有在let命令所在的代码块内有效
{
let a = 10; var b = 1;
}
a // ReferenceError: a is not defined. let声明的只能在所在的代码块内有效,否则报错
b // 1 var声明的不存在块级作用域
好处:例如一般用在for循环中可解决循坏计数暴露为全局变量的问题 在for外部使用循环变量时会报错 console.log(i); // ReferenceError: i is not defined
内层变量可能会覆盖外层变量的问题
2)let声明的变量不存在变量提升(即声明后才可使用,否则会报错。而var声明的变量存在变量提升,在自己的作用域内提升)
console.log(foo);// 输出undefined 提升后 var foo 会在console.log前
var foo = 2
console.log(foo);//报错ReferenceError 即在声明前使用就会报错
let foo = 2
3) 暂时性死区。在代码块内,使用let命令声明变量之前,该变量都是不可用的,会报错,就是在声明前都是它的死区
var tmp = 123;
if(true){
tmp = ‘abc’ ;// ReferenceError
let tmp;
}
typeof不再是一个百分之百安全的操作,之前es5中,它是一个安全的操作,即使没声明的变量也会是undefined,不会报错
而用let声明的变量,在声明前检查它的类型会报错
总结:在块内用let声明了变量,就对绑定在这个块,在这个块内,只要声明前使用这个变量就会报错,不会去外部作用域去寻找
4)变量不允许重复声明 ( let不允许在相同作用域内,重复声明同一个变量)
let a = 10
var a = 1;此段代码会报错的
let并且不允许在函数内部重新声明参数,若在另一个块级作用域声明则不会报错
function f(arg){
let arg
}
f() // 报错
注意⚠️:在块级作用域中不要区声明一个函数,优先使用函数表达式来定义
2、const
1)声明一个只读的常量。一旦声明,常量的值就不能改变且必须立即初始化
const PI = 3.1415;
PI = 3;// TypeError
const PI // TypeError,只声明不赋值也会报错
注意⚠️:对于简单的数据类型值是固定不变的,但对于复杂的数据类型,是指向的指针是固定的,至于往里面加属性方法是可以的,若重新赋值一个例如对象,会报错
若真想对一个对象冻结,可用Object.freeze()方法
2)const的作用域与let命令相同:只在声明所在的块级作用域内有效
3)与let同,也不存在变量提升,有暂时性死区(在代码块内,声明前使用就会报错)
3、顶层对象的属性(浏览器环境指的是window对象,在 Node 指的是global对象):es5中顶层对象的属性与全局变量是等价的。
ES6中规定:var、function声明的全局变量,依旧是顶层对象的属性;而let命令、const命令、class声明的全局变量,不属于顶层对象的属性。
即: let b = 1
window.b // undefined,不会像 es5一样直接是变量b的值
ES6中引入globalThis作为顶层对象。也就是说,任何环境下,globalThis都是存在的,都可以从它拿到顶层对象,指向全局环境下的this。

三、变量的解构赋值
1、数组的解构赋值(即按照模式匹配只要等号两边的模式相同,左边的变量就会被赋予对应的值)
1)模式相同匹配成功赋值
2)匹配不成功 let [foo]=[]或 let [bar,foo]=[1] 都解构不成功时变量的值为undefined
3)不能完全匹配(等号左边的模式,只匹配一部分的等号右边的数组). let [x,y]=[1,2,3] 此时前两个解构成功
4)报错。当等号右边不是可遍历的结构则会报错。let=[foo]=1 /{}/null/false/undefined/NaN
5) 解构赋值允许指定默认值(只有数组成员严格等于undefined,默认值才会生效)
⚠️默认值可以引用解构赋值的其他变量,但该变量必须已经声明
let [x=y,y=1]=[ ] // ReferenceError: y is not defined
2、对象的解构赋值(属性没有次序,变量必须与属性同名,才能取到正确的值)
1)当解构不成功时,变量的值为 undefined 例如:let{foo}={bar:“baz”}
2)对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量
let {sin, cos , max, min}=Math 将Math对象的方法赋给对应的变量。sin//Math.sin
3) 若变量名与属性名不一致,要想解构成功,必须写成以下形式:

let{foo:baz}={foo:"aaa",nnn:"bbb"} //  baz//"aaa",冒号后是新变量,前是对应的属性
// 真正被赋值的是后者

4)指定默认值(默认值生效也是对象的属性值严格等于undefined)
let {x=1}={} //变量x的值1 let {x:y=3}={} //变量y的值3 let{x=3}={x:undefined} //变量x的值3
注意点⚠️ 当使用已经声明的变量进行对象的解构赋值时,不可将大括号写在行首,因为j s会解析成代码块,此时可用小括号。 let x; ({x}={x:1})
允许等号左边不放置任何东西,无意义,但语法合理。({}={x:1})
因数组是特殊的对象,可用于对象属性的解构,此时索引就是对应关系
3、字符串的解构赋值(字符串被转换成了一个类似数组的对象)
let[a,b,c,d,e]=“hello” 此时变量a的值为字符串“h”
可对对象的length属性解构赋值。let{length:len}=“hello” 此时 Len为5
4、数值和布尔值的解构赋值
如果等号右边是数值和布尔值,则会先转为对象
Number.prototype.toString
5、函数的解构赋值:函数的参数也可以用于解构赋值,内容规则同上
6、圆括号问题
1)变量声明语句中不可使用圆括号 let[(a)]=[1]
2)函数参数中不可使用圆括号
3)赋值语句的模式不可使用圆括号. ( {a:aa})={a:1}//报错
4)赋值语句的非模式可使用圆括号 ( {a:aa}={a:1})

四、字符串的扩展
1、字符的unicode表示法"\u{}" 将码点放入大括号,解读该字符 允许\uxxxx表示一个字符,xxxx是字符对应码点的16进制表示法
2、字符串的遍历接口( 可以被for…of循环遍历 for(let i of “hello”) 识别32位字符(4个字节)
3、可直接输入行分隔符和段分隔符
4、JSON.stringify()将对象转为字符串
5、模版字符串是增强版的字符串,用反引号(`)标识,变量的拼接不用+,而用${}
es5中js字符串方法
1、.concat()将多个字符串拼接成一个新的字符串
2、.slice()字符串截取,返回截取到的子符串,支持负数,负数表示倒数第几位开始
3、.indexOf()给特定字符串查索引,返回该字符串第一次出现的位置
.lastIndexOf()给特定字符串查索引,返回该字符串最后一次出现的位置
4、.charAt()在索引处查找对应字符 str.charAt(0)
5、.charCodeAt()返回索引处字符对应的Unicode值 str.charAt(0)
6、.toUpperCase()将字符串中字母转换成大写字母
7、toLowerCase()将字符串中所有字母转换成小写字母
8、.replace()将字符串中某个子串以特定字符串替代(不是全局替换)
9、.split()将字符串转为数组 无参将整体作为一个,“”即每个字符为一个数组值
10、.match()使用正则表达式搜索目标子字符串,返回匹配的子字符串
11、.search()使用正则表达式搜索目标子字符串,返回匹配的索引值
12、.trim()去除前后空格 有兼容问题
13、String.fromCharCode(ASKII)返回码点对应的字符(注意:不识别大于0xFFFF字符)
es6扩展
1)String.fromCodePoint() 返回码点对应的字符,若多个参数合并成一个返回,能识别32位4字节的字符,用法同String.fromCharCode()
2)String.raw()该方法将字符串\转义
实例方法
3).codePointAt()返回索引处字符的码点(可以处理4个字节存储的字符)同.charCodeAt()
4)查找子字符串的方法,返回都是布尔值,第二个参数表示开始搜索位置
.includes(参)是否找到了参数字符串
.startsWith()参数字符串是否在原字符串头部
.endsWith()参数字符串是否在原字符串尾部
5).repeat(n)将原字符串重复n次,返回新字符串,原字符串不变,若0次则‘’
6).padStart(长度,用什么补)在头部补全到指定长度,参数<=原字符串长度,返回原则字符串,否则返回新字符串 若省略第二参数,默认空格补
.padEnd(长度,用什么补) 类同上面
7).trimStart()去除头部空格 .trimEnd()去除尾部空格 对tab键 换行符等不可见的空白有效

五、正则的扩展
1、RegExp构造函数的参数只能是字符串或者正则表示式
var regex = new RegExp (“”,修饰符)
var regex = new RegExp (/正则表达式/) 正则.test(字符串) 参数是否符合正则表达式,返回布尔.当使用正则表达式时,不可以使用第二参来添加修饰符,否则会报错,es6中允许使用第二参数,此时返回的正则表达式会忽略原有的正则表达式的修饰符,只使用新指定的修饰符
例如:new RegExp(/abc/ig,“I”)此时正则的修饰符是i
2、字符串的正则方法。
.match(正则)使用正则表达式搜索目标子字符串,返回匹配的子字符串 实际是String.prototype.match
.search(正则)使用正则表达式搜索目标子字符串,返回匹配的索引值
.replace()将字符串中某个子串以特定字符串替代
.split()将字符串转为数组 无参将整体作为一个,“”即每个字符为一个数组值
es6在语言内部做了调整, 让所有与正则相关的方法,全都定义在RegExp对象上。
3、u修饰符(用来正确处理四字节的utf-16)且可以使用大括号包住表示 Unicode 字符,这种表示法在正则表达式中必须加上u修饰符,才能识别当中的大括号
例如/^\uD83D/u
4、正则实例对象新增.unicode属性,表示是否设置了u修饰符。RegExp.prototype.unicode 会返回布尔类型值
5、新增y修饰符,叫做“粘连”修饰符,全局匹配。g修饰符只要剩余位置中存在匹配就可,而y修饰符确保匹配必须从剩余的第一个位置开始
6、正则实例对象多了sticky属性,表示是否设置了y修饰符 RegExp.prototype.usticky 会返回布尔类型值
7、正则表达式新增了flags属性,会返回正则表达式的修饰符
8、s修饰符使得.可以匹配任意单个字符(之前点不可以匹配回车换行 行分隔符 段分隔符)
且给正则实例增加了属性dotAll 返回布尔表示是否使用了s修饰符
9、具名组匹配 正则表达式使用圆括号进行组匹配
10、String.prototype.matchAll()方法,可以一次性取出所有匹配。不过,它返回的是一个遍历器,而不是数组,解决了es5中一次次的去匹配取出gy

六、数值的扩展(减少了一些对应es5的全局方法)
1、二进制和八进制数值的新的写法 0b或B。 0o或0O
0b111110111 === 503 // true 0o767 === 503 // true
2、Number.isFinite()判断一个数是否是有限的, Number.isNaN()判断一个数是否是NaN 它们只对数值有效,不进行类型的转换
3、Number.parseInt(), Number.parseFloat() 与es5一致,会进行类型的转换
4、Number.isInteger() 判断一个数值是否为整数,参数不是数值直接false
5、Number.EPSILON 表示 1 与大于 1 的最小浮点数之间的差
6、Number.isSafeInteger() 整数范围在-253到253之间(不含两个端点) 判断是否为安全整数
js能准确表示的整数范围是-253到253。 Number.MAX_SAFE_INTEGER和Number.MIN_SAFE_INTEGER用来表示这个范围的上下限
例如:Number.MAX_SAFE_INTEGER === Math.pow(2,53) - 1 // true

7、==Math对象的扩展
Math.trunc()方法用于去除一个数的小数部分,返回整数部分 会进行类型的转换
Math.sign()方法用来判断一个数到底是正数、负数、还是零。对于非数值,会先将其转换为数值
参数为正数,返回+1;
参数为负数,返回-1;
参数为 0,返回0;
参数为-0,返回-0;
其他值,返回NaN。
Math.cbrt()方法用于计算一个数的立方根
Math.clz32()方法将参数转为 32 位无符号整数的形式,然后返回这个 32 位值里面有多少个前导 0 先转为二进制补齐32位,看前导 0有多少个
Math.imul()方法返回两个数以 32 位带符号整数形式相乘的结果,返回的也是一个 32 位的带符号整数。即返回两个数相乘的结果
Math.fround()方法
Math.hypot()方法返回所有参数的平方和的平方根
Math对象新增了4个对数相关的方法
Math.expm1(x)返回 ex - 1,即Math.exp(x) - 1
Math.log1p(x)方法返回1 + x的自然对数,即Math.log(1 + x)。如果x小于-1,返回NaN。
Math.log10(x)返回以 10 为底的x的对数。如果x小于 0,则返回 NaN
Math.log2(x)返回以 2 为底的x的对数。如果x小于 0,则返回 NaN
8、新增了一个指数运算符(**)
9、BigInt 数据类型(大整数) BigInt 只用来表示整数,没有位数的限制,任何位数的整数都可以精确表示 即须添加后缀n。123n
⚠️以使用负号(-),但是不能使用正号(+) -123n可以。 正不可以
可以将数转为大整型。 BigInt(123) // 123n

七、函数的扩展
1、函数参数的默认值(参数默认值是惰性求值,每次都会重新求,而不是默认固定的 )。一般默认值写在尾参数的位置,容易看出来那些参可以省,如果写在别的位置,实质上是不可以省的
好处:可立刻意识到哪些参数是可以省略的,不用查看函数体或文档;其次,有利于将来的代码优化,即使未来的版本在对外接口中,彻底拿掉这个参数,也不会导致以前的代码无法运行
⚠️ 函数的参数是默认声明的,不可再用let const重复声明
⚠️ 在使用默认参数时,不可有同名的参数。如:function(x,x,y)可以。但function(x,x,y=1)就会报错
1)直接写在参数定义的后面。function(x,y=0)
2) 可用解构赋值来指定默认值(即严格等于undefined时,默认值才会生效)
2、函数的length属性。函数的length属性,将返回没有指定默认值的参数个数(即不是真实的参数个数) 默认参数后面的参数都不会记
3、作用域:在使用默认参数后,参数进行声明初始化时,参数会形成一个单独的作用域(不是去全局找)
4、rest参数(该变量将多余的参数放入数组中) …变量名 用于获取函数的多余参数,它只能是最后一个参数,否则报错,length属性也不包含此参数
⚠️es5用的是伪数组arguments对象,当函数调用时,函数的参数会传入这个数组对象中
5、严格模式
es5中函数的内部可以设置严格模式’use strict’
es6规定只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错6
6、函数的name属性(返回函数的名字,字符串类型)
1)匿名函数的变化:将一个匿名函数赋值给一个变量,ES5 的name属性,会返回空字符串,而 ES6 的name属性会返回实际的函数名。
7、箭头函数(=>)定义函数箭头函数,箭头后面的就是函数体部分。不需要参数或需要多个参数,就使用一个圆括号代表参数部分
如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return语句返回。若返回的是一个对象用小括号扩起来,否则会解析成代码块,而非函数体
如果箭头函数只有一行语句,不用括起来

    使用注意点⚠️:1)函数体内的this对象,继承自定义时所在的作用域。  即this指向是固定的跟调用模式无关
                              2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。因为没有constructor、prototype
                              3)不可以使用arguments对象,可以用 rest 参数代替。
                              4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。
    使用注意点⚠️:不用于对象中方法(对象中的方法不用箭头函数定义,因为一般我们希望this指向该对象,而对象不构成作用域所以会使this指向全局或是上层作用域,改变初衷)但这种方式可以固定this指向,普通函数可能因调用方式的不同使this指向不同
                              5)不能使用apply、call、bind修改this指向,因为它无自身this,传了也会忽略
// 案例1
类中箭头函数是放在实例中的,普通函数在原型中
// 案例2
const object = {
 a: 1,
 b: () => { // 指向window,定义时所在的作用域中
 console.log(this.a);
 }, 
 c: function () { // 会因调用方式不同指向不同
 console.log(this.a)
 },
}
object.b();
object.c();
const x = object.c;
x();
// 案例3
function Person() {
  this.age = 0;
  setInterval(function growUp() { // 定时器中this指向window,可以通过存储变量拿到对象中this
    this.age++;
  }, 1000);
}
var p = new Person();
1)apply、call、bind的区别
    apply:克隆函数,改变this,传入数组参数,执行后函数立即执行
    call:克隆函数,改变this,传入参数序列,执行后函数立即执行
    bind:克隆函数,改变this,传入参数序列,执行后函数不立即执行
    
(2)如何修改定时器this指向
    apply、call不能用于修改定时器this,因为会立即执行失去定时器的意义
    1)保存变量,利用作用域链修改this指向
		    var obj = {
		    dd:666,
		    tt(){
		        that = this
		        setTimeout(function(){
		            console.log(that.dd)
		        },1000)
		     }
		   }
		 obj.tt() // 66
    
    2)使用bind(返回一个函数)
		var obj = {
		    dd:666,
		    tt(){
		        setTimeout(fn.bind(this),1000)
		    }
		}
		obj.tt()
   
   3)使用箭头函数(利用箭头函数无this,继承拿到)
	   var obj = {
	    dd:666,
	    tt(){
	        setTimeout(()=>{
	            console.log(this.dd)
	        },1000)
	    }
	  }
	  obj.tt()3)如何修改箭头函数this指向
    apply、call、bind不能用于修改箭头函数this,因为箭头函数无自身this,来自继承
    一般不修改,定义时生效的,要不不要使用 


// 模拟实现 call方法(将函数添加至新对象中方法,执行再删除。参数:)
	Function.prototype.call2 = function (context) { // 模拟实现call
	    var context = context || window; // 兼容null时指向window
	    context.fn = this; // 给新指向的函数执行添加方法(保存新的this指向)
        //  处理参数序列 
	    var args = [];
	    for(var i = 1, len = arguments.length; i < len; i++) {
	        args.push('arguments[' + i + ']');
	    }
	
	    var result = eval('context.fn(' + args +')'); // 处理返回
	    delete context.fn
	    return result;
	}

	// 测试一下
	var value = 2;
	var obj = {
	    value: 1
	}
	function bar(name, age) {
	    console.log(this.value);
	    return {
	        value: this.value,
	        name: name,
	        age: age
	    }
	}
	bar.call2(null); // 2
	console.log(bar.call2(obj, 'kevin', 18));
	// 1
	// Object {
	//    value: 1,
	//    name: 'kevin',
	//    age: 18
	// }


// apply的实现,与call类似,参数是数组
Function.prototype.apply = function (context, arr) {
    var context = Object(context) || window;
    context.fn = this;
    // 开始处理参数
    var result;
    if (!arr) { // 没传时
        result = context.fn();
    }
    else { // 传了数组参数时
        var args = [];
        for (var i = 0, len = arr.length; i < len; i++) {
            args.push('arr[' + i + ']');
        }
        result = eval('context.fn(' + args + ')') // 传一次参数执行
    }
    delete context.fn
    return result;
}
    

8、尾调用优化:只保存内层函数的调用帧(节省内存,直接用内层函数的调用帧,取代外层函数的调用帧就可以,因为是函数的最后一步其他也无需保存了)即在函数的最后一步纯调用另一函数(只要是函数的最后一步即可,是函数的最后一步操作即可)
尾递归:尾部纯调用自己,只保存最后一个调用帧不会发生栈溢出(递归指自己调用自己)

// 实例
function f(){
g(x) // 不是尾调用,因为还会执行return undefined
}

// 尾递归案例 阶乘 1*2*n
function f(n,total=1){
if(n===1) return total
return f(n-1,n*total)
}

f(n,c1,c2){
if(n<=1) return c2
return f(n-1,c2,c1+c2)
}

9、函数参数的尾逗号:允许在最后一个参数后面出现参数
10、Function.prototype.toString() 对实例的方法做了修改,要求返回一模一样的函数字符串,注释空格不可以省

八、数组的扩展
es5中数组方法
1、 Array.push()在数组最末尾插入元素,改变了数组长度,返回数组的长度,原数组改变了
2、 Array.pop()在数组最末尾删除一项,返回删除项,原数组改变了(去掉了最后一项)
3、 Array.unshift()在数组的最前面添加元素,返回数组长度,原数组改变了
4、 Array.shift()在数组的最前面删除一项,返回删除项,原数组改变了=
5、 Array.reverse()数组的翻转,返回翻转后结果,原数组改变了
6、 Array.sort()数组的排序,默认升序排列,可以函数作为参数指定降序等,返回排序后结果,原数组也变为排序后结果
7、Array.indexOf()即给字符查索引,返回对应索引值(缺点查不了NaN)联想.findIndex()
8、Array.concat()数组的连接,可将多个数组连接成一个新数组,返回连接成的新数组(原先各数组不会改变)
9、Array.slice()数组的截取,一个参数表示从哪开始截取。两个参数包左不包右。返回截取到的数组,负数从倒数开始算
10、Array.splice(开始位置, 删除的个数,元素)万能方法,可以实现增删改:返回的是截取到的新数组,无截取到则返回[] 注意:原数组也改变了
11、Array.toString()数组转为字符串,返回转成的字符串
12、Array.join()数组转为字符串 不写参数默认逗号即1,4,5这种 “”无缝连接 或可以指定字符连接
数组迭代方法
1)Array.map()数组中的每个元素调用一个提供的函数,结果作为一个新的数组返回,原来数组不变
2)Array.forEach()遍历数组,无返回值,直接改变原数组 注意和.map()区分
3)Array.every()将所有元素进行判断返回一个布尔值,如果所有元素都满足判断条件,则返回true,否则为false
4)Array.some()将所有元素进行判断返回一个布尔值,如果存在元素都满足判断条件,则返回true,若所有元素都不满足判断条件,则返回false
5)Array.filter()将所有元素进行判断,将满足条件的元素作为一个新的数组返回
6)Array.reduce()所有元素调用返回函数,返回值为最后结果,参数是函数
es6扩展
1)扩展运算符… 实质调用数据结构的iterator接口,将数组转为用逗号分隔的参数列表 可替代函数的apply方法
… 将数组转成用逗号分隔的序列,一般用于函数参数rest参数将对于参数放入数组中(或数组最为参数列表时使用)
替代函数的apply方法将数组参数转为序列参数 f.apply(null,[1,2])
用于数组的合并、与结构赋值结合
可将实现了iterator迭代器的伪数组转为真正的数组(对象不可以,没有实现iterator报错)
2)Array.from() 用于将两类对象转为真正数组 1、可遍历的iterator 2、类似数组的对象(就是有length属性)
Array.from(new Set(arr)) // set类似数组但成员都是唯一的
Array.from(arr,x=>x*x) // 返回函数处理后的数组结果
3)Array.of() 将一组数值转为数组 弥补了Array()的缺陷Array(3)即[,,] 而Array.of(3)即[3]
比较统一:总是返回参数组成的数组
4)arr.copyWithin()三个参数 当前数组内部将指定位置的成员复制到其他位置

参数:开始替换数据的位置(必须)、读取数据开始位置(默认0)、读取数据结束位置(默认长度,有值不包含该位置处的)负数会 转成+数组长度
[1,2,3,4,5].copyWithin(0,3)0位置开始替换,读取 3到最后 // 4,5,3,4,5

5)arr.find() 找出第一个符合条件的数组成员,若都不符合返回undefined 它的参数为一个回调函数(接受三个参数) 第二个参数用来绑定回调函数中this对象
arr.findIndex() 它返回的是第一个符合条件的值的索引 可以发现NaN 弥补indexof的不足,无-1

[1,2,3,4].find((x,index,arr)=>x>3) // 4 值、位置、原数组
[1,2,3,4].findIndex((x,index,arr)=>x>3) // 3 值、位置、原数组

6)arr.fill(2,0,1) 用给定值填充一个数组 。接受第二、第三个参数表示填充的起始结束位置(不写的话默认从头填充到尾)

[1,2,3].fill(7,0,2) // 0,1位置用7填充 [7,7,3]

7)数组实例的entries、keys、values用于遍历数组,返回的视遍历器,用于遍历数组
8)arr.includes() 判断某个数组是否包含了给定值,返回布尔值 可以接受第二参数表示搜索的起始位置 可以正确判断NaN,负数则表示倒数位置,若负数超出长度则0开始
9)arr.flat() 将嵌套的数组拉平 默认拉平一层 可以设想要拉平层数 Infinity全部拉平
10)arr.flatMap() 第一个参数函数(接受三个参数),第二个绑定this对象
先执行函数返回结果组成的新数组,在执行flat拉平一层
11)数组的空位
es5中对空位的处理:forEach、filter、some、every跳过空位
map执行时跳过但会保留这个值
join、toString视为undefined,undefined、null处理成空串
es6将空位视为undefined

伪数组:具有length属性,可遍历,但不具备数组的各方法

伪数组转为真数组方法
1)Array.prototype.slice.call(arguments)
2[…arguments]
3)Array.from(arguments)
// (1)是否实例的判断:不准因为所有的引用类型都是对象的实例 arr.instanceof Object true
arr instanceof Array  
// (2) 判断它的构造函数是否数组:
arr.constructor===Array
//(3)es6提供的方法:有些低版本浏览器不支持
Array.isArray(arr)
// (4) 通用的toString方法
Array.prototype.toString.call(arr)==='[object Array]'

找出数组中最大值方法

1 Math.max.apply(null,arr) 利用apply可传数组作为参数,因为Math.max的参数 不是数组
2 Math.max.call(null,1,2,3,6)
3 arr.sort().reverse()[0]
4 arr.reduce(function(a,b){
return b>a?b:a;
)

九、对象的扩展
1、属性的简结表示法(允许在对象中写入变量或者函数)。
const foo = ‘bar’;
const baz = {foo};
baz // {foo: “bar”}
对象中方法也可以简洁表示省略function。 method(参数){代码块}. 原来写法method:function(){}
2、name属性,对象方法也是函数,因此也有name属性
bind方法创造的函数,name属性返回bound加上原函数的名字;
Function构造函数创造的函数,name属性返回anonymous
如果对象的方法是一个 Symbol 值,那么name属性返回的是这个 Symbol 值的描述
3、对象中属性的可枚举性和遍历
Object.getOwnPropertyDescriptor(对象名,属性)方法可以获取该属性的描述对象// { value: 123, writable: true, enumerable: true, configurable: true }
有四个操作会忽略不可枚举的属性
for…in循环:只遍历对象自身的和继承的可枚举的属性。 要是对自己属性的操作 还应判断 obj.hasOwnProperty(key)
Object.keys():返回对象自身的所有可枚举的属性的键名。
JSON.stringify():只串行化对象自身的可枚举的属性。
Object.assign(): 忽略enumerable为false的属性,只拷贝对象自身的可枚举的属性。
Object.getOwnPropertyNames(obj)返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名
Object.getOwnPropertySymbols(obj)返回一个数组,包含对象自身的所有 Symbol 属性的键名
Reflect.ownKeys(obj)返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举
4、super关键字(类似this关键字)指向当前对象的原型对象 ⚠️只能用在对象的方法中,其他地方会报错
5、对象的扩展运算符(…对象。用于取出参数对象的所有可遍历属性,拷贝到当前对象之中). 即类似对象的拷贝。Object.assign({},要拷贝过来的对象)方法
例如:const z={a:4,b:5}. const c={…z}.
6、链判断运算符。?.判断是否存在 原来是===“undefined”
obj?.prop // 对象属性
obj?.[expr] // 对象属性
func?.(…args) // 函数或对象方法的调用
7、Nul l判断运算符 ?? 行为类似||,但是只有运算符左侧的值为null或undefined时,才会返回右侧的值
读取对象属性的时候,如果某个属性的值是null或undefined,有时候需要为它们指定默认值。常见做法是通过||运算符指定默认值
const headerText = response.settings.headerText || ‘Hello, world!’;

对象的新增方法
1、Object.is() 解决es5的缺陷 es5 比较两个值是否相等,只有两个运算符:相等运算符()和严格相等运算符(=)。它们都有缺点,前者会自动转换数据类型,后者的NaN不等于自身,以及+0等于-0.
⚠️:空对象是不等于空对象,它是复杂数据类型
2、Object.assign(目标对象,源对象)。对象的合并,将源对象中所有可枚举的属性复制到目标对象。 若参数不是对象会先进行转换,nu l l和undefined没法转,会报错。实现的是浅拷贝
3、Object.getOwnPropertyDescriptors(ob j)返回某个对象属性的描述对象
4、__proto__属性,用来读取或设置当前对象的原型对象
Object.setPrototypeOf方法的作用与__proto__相同,用来设置一个对象的原型对象
5、Object.keys(obj)方法,返回一个数组,成员是对象自身的(不含继承的)所有可遍历属性的键名
Object.values(obj)方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历属性的键值
Object.entries(obj)方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历属性的键值对数组
6、Object.fromEntries()方法是Object.entries()的逆操作,用于将一个键值对数组转为对象

十、Symbol(数据类型,不是构造函数,不可用new):可用于创建独一无二的值,不存在相等重名的情况
凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突
1、声明:let cc=Symbol() 可以接受一个字符串作为参数,表示对 Symbol 实例的描述,即使参数同,两个symbol值也不相等,只是利于区分哪个是哪个
2、可以转字符串类型、布尔类型,不可转数值
3、实例属性 Symbol.prototype.description 可以返回它的描述
4、Symbol 值作为对象属性名时,不能用点运算符添加和查询,因为点运算后总是字符串,因此不会读取symbol属性名
遍历Symbol 对象属性名 Object.getOwnPropertySymbols(obj)方法,可以获取指定对象的所有 Symbol 属性名。该方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值 得到的是属性名组成的数组
5、创建和使用同一Symbol 值
Symbol.for()接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建一个以该字符串为名称的 Symbol 值,并将其注册到全局
let s1 = Symbol.for(“foo”)
let s2 = Symbol.for(“foo”)此时它们值相等
Symbol.keyFor(s1)方法返回一个已登记的 Symbol 类型值的key,无就是undefined
6、内置的 Symbol 值 提供11内置Symbol 值

十一、Set和Map数据结构
1、Set 集合新的数据结构,类似数组,但不可有重复的值,是一个构造函数,用来生成Set 数据结构 let h=new Set()
作用 :可以给数组或者字符串去重
实例的属性和方法
Set.prototype.constructor 它的构造函数,默认就是Set函数。
Set.prototype.size:返回Set实例的成员总数
Set.prototype.add(value):添加某个值,返回 Set 结构本身。
Set.prototype.delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
Set.prototype.has(value):返回一个布尔值,表示该值是否为Set的成员。
Set.prototype.clear():清除所有成员,没有返回值。
四个遍历方法
Set.prototype.keys():返回键名的遍历器
Set.prototype.values():返回键值的遍历器
Set.prototype.entries():返回键值对的遍历器
Set.prototype.forEach():使用回调函数遍历每个成员
2、WeakSet不重复的值的集合 但WeakSet 的成员只能是对象,WeakSet 中的对象都是弱引用。是构造函数
⚠️具有 Iterable 接口的对象,都可以作为 WeakSet 的参数
WeakSet.prototype.add(value):向 WeakSet 实例添加一个新成员。
WeakSet.prototype.delete(value):清除 WeakSet 实例的指定成员。
WeakSet.prototype.has(value):返回一个布尔值,表示某个值是否在
3、Map 类似对象也是健值对的集合,但是健的范围扩展了,不只是字符串 是构造函数,用来生成Map 数据结构
实例属性和方法
.size属性返回 Map 结构的成员总数
.set(key, value) 添加
.get(key)属性对应值
.has(key) 布尔
.delete(key)布尔
.clear() 清除无返回值
Map.prototype.keys():返回键名的遍历器。
Map.prototype.values():返回键值的遍历器。
Map.prototype.entries():返回所有成员的遍历器。
Map.prototype.forEach():遍历 Map 的所有成员。
4、WeakMap 类似Map 生成键值对的集合但是健名只能是对象(null除外),键名所指的对象弱引用。构造函数
应用DOM 节点作为键名,不用手动删除
.set(key, value) 添加
.get(key)属性对应值
.has(key) 布尔
.delete(key)布尔

十二、Proxy 是构造函数,用于生成Proxy实例。是一种元编程,修改语言内部的默认行为(即外界对某对象的访问,先通过这层拦截)。可以对外界的访问过滤和改写
let proxy=new Proxy(目标对象,拦截对象)
对象的实例方法:
1、get(target, propKey, receiver):拦截对象属性的读取,第三参可选
2、set(target, propKey, value, receiver):拦截对象属性的设置
注意,如果目标对象自身的某个属性,不可写且不可配置,那么set方法将不起作用。
严格模式下,set代理如果没有返回true,就会报错。
3、has(target, propKey):拦截propKey in proxy的操作,返回一个布尔值
如果原对象不可配置或者禁止扩展,这时has拦截会报错
has方法拦截的是HasProperty操作,而不是HasOwnProperty操作,即has方法不判断一个属性是对象自身的属性,还是继承的属性
4、deleteProperty(target, propKey)
5、ownKeys(target):拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for…in循环,返回一个数组。该方法返回目标对象所有自身的属性的 属性名,而Object.keys()的返回结果仅包括目标对象自身的可遍历属性
6、getOwnPropertyDescriptor(target, propKey):拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象
7、defineProperty(target, propKey, propDesc):拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值
8、preventExtensions(target):拦截Object.preventExtensions(proxy),返回一个布尔值
9、getPrototypeOf(target):拦截Object.getPrototypeOf(proxy),返回一个对象
10、isExtensible(target):拦截Object.isExtensible(proxy),返回一个布尔值
11、setPrototypeOf(target, proto):拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截
12、apply(target, object, args):拦截 Proxy 实例作为函数调用的操作,比如proxy(…args)、proxy.call(object, …args)、proxy.apply(…)
13、construct(target, args):拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(…args)

十三、Reflect 从Reflect对象上可以拿到语言内部的方法,不是构造函数
13个静态方法,用于获取语言内部方法,与Proxy是对应的

Reflect.apply(target, thisArg, args)
Reflect.construct(target, args)
Reflect.get(target, name, receiver)
Reflect.set(target, name, value, receiver)
Reflect.defineProperty(target, name, desc)
Reflect.deleteProperty(target, name)
Reflect.has(target, name)
Reflect.ownKeys(target)
Reflect.isExtensible(target)
Reflect.preventExtensions(target)
Reflect.getOwnPropertyDescriptor(target, name)
Reflect.getPrototypeOf(target)
Reflect.setPrototypeOf(target, prototype)

十四、Promise对象是一个构造函数,用来生成实例(实现异步的办法)
const promise=new Promise (function(resolve,rejest){
//要执行的异步操作,resolve,rejest函数是内部提供的,根据异步操作的执行结果,更新实例的状态,将结果作为此函数的参数传递出去
})
1、特点:对象的状态不受外界影响,只有异步操作的结果,可以决定当前是哪一种状态
一旦状态改变,就不会再变
2、缺点:一旦新建就会立即执行,中途无法取消
若不设置对应的回调函数,内部抛出的错误无法反应到外部
在进行时,无法知道执行到哪一步了
3、实例方法(定义在构造函数的原型对象上)
.then 接受两个函数参数,指定状态下对应的回调函数,参数就是上一个promise实例穿出来的参数
.catch 对抛出的错误做处理,即异步操作失败执行的回调函数
.finally 跟实例的状态变更无关,都会执行的操作,回调函数不接受参数
4、Promise对象方法
Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例
Promise.race()方法将多个 Promise 实例,包装成一个新的 Promise 实例
Promise.allSettled()方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例
Promise.any()方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例
它们都是返回新的实例,但实例的状态变更原则与传入对应回调函数的参数是各有不同的
Promise.resolve() 将现有对象转为Promise 实例并返回
1)如果参数是 Promise 实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例
2)具有then方法的对象,将这个对象转为 Promise 对象,然后就立即执行then方法
3)不是对象,或者是一个不具有then方法的对象,返回一个新的 Promise 对象,状态为resolved
4)无参 直接返回一个resolved状态的 Promise 对象

十五、遍历器和for of循环
遍历器是一个接口,为各个数据结构提供访问机制,部署在数据结构的Symbol.iterator属性上
它的本质就是一个指针。指向起始位置,用next方法遍历,直到数据结构的最后一个位置,每次调用next方法,都会返回一个代表当前成员的信息对象,具有value和done两个属性{value:,done:}
原生具备 Iterator 接口的数据结构如下。 可使用for of遍历
Array
Map
Set
String
TypedArray
函数的 arguments 对象
NodeList 对象

十六、Generator 函数的语法 Generator 函数是一个状态机,封装了多个内部状态。执行 Generator 函数会返回一个遍历器对象,而不是去执行对象本身
1、形式上:有两个特征一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式,定义不同的内部状态
⚠️执行 Generator 函数会返回一个遍历器对象,而不是去执行对象本身
每次调用遍历器对象的next方法,遇yield命令暂停,返回{value:yield表达式值,done:是否遍历结束} 若方法有参数,则就是value值
当使用for of循环时,不会返回最后一个值,即done为true的属性值
2、遍历器对象方法
Generator 函数返回的遍历器对象,都有一个throw方法,可以在函数体外抛出错误,然后在 Generator 函数体内捕获catch
Generator 函数返回的遍历器对象,还有一个return方法,可以返回给定的值,并且终结遍历 Generator 函数
⚠️:不提供参数,则返回值的value属性为undefined
:如果 Generator 函数内部有try…finally代码块,且正在执行try代码块,那么return方法会导致立刻进入finally代码块,执行完以后,整个函数才会结束

十七、Generator 函数的异步应用
实现原理;需暂停的地方用yield命令
使用next来实现与函数体内与向函数体外数据传递

十八、async函数 对Generator 函数的改进,也是实现异步操作 但它内置执行器,不用手动使用next方法或co模块
使用注意点:1)await命令后面的Promise对象,运行结果可能是rejected,所以最好把await命令放在try…catch代码块中
2)多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发
3)await命令只能用在async函数之中,如果用在普通函数,就会报错

十九:类Class跟构造函数的用法一致,类中的方法都定义在类的原型上,实例都可继承
注意点⚠️:必须用new创建实例,否则报错
方法上不要function,且方法间不要逗号
类中方法都是不可枚举的
不存在变量提升
当在方法前加static关键字时,表明是静态方法,只能被类调用,不可被实例继承使用,静态方法中的this指向类而不是对象实例
当实例创建后自动执行构造方法,类中没有定义构造方法,则默认添加一个空的构造方法

二十:Class的继承
1、类的继承 用extends关键字来实现继承(父类的静态方法也会被子类继承)
class B extends A{
}
注意点⚠️子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,
得到与父类同样的实例属性和方法,然后再对其进行加工,加上 子类自己的实例属性和方法。如果不调用super方法,子类就得不到this对象
2、Object.getPrototypeOf方法可以用来从子类上获取父类(相当于父就是它的原型,它继承父的属性和方法)
3、super关键字
1)super作为函数使用时,只能用在子类的构造函数中,指向父类的构造方法,返回子类实例(即this指向子类实例)
2)在普通方法中作为对象使用时,指向父类原型(父类实例上增加的属性和方法访问不了),方法中this指向子类实例
3)在静态方法中作为对象使用时,指向父类,this指向子类(即找静态方法和静态属性中查找,就是类自己本身的)
4、类的prototype属性和__proto__属性
(1)子类的__proto__属性,表示构造函数的继承,总是指向父类。
(2)子类prototype属性的__proto__属性,表示方法的继承,总是指向父类的prototype属性
5、实例的 proto 属性
实例的__proto__属性的__proto__属性,指向父类实例的__proto__属性

二十一:修饰器

二十二、Module的语法(模块)浏览器和服务器通用的模块化解决方案。在编译时完成模块的加载
1、ES6 的模块自动采用严格模式,不管你有没有在模块头部加上"use strict";
主要有以下限制:

变量必须声明后再使用
函数的参数不能有同名属性,否则报错
不能使用with语句
不能对只读属性赋值,否则报错
不能使用前缀 0 表示八进制数,否则报错
不能删除不可删除的属性,否则报错
不能删除变量delete prop,会报错,只能删除属性delete global[prop]
eval不会在它的外层作用域引入变量
eval和arguments不能被重新赋值
arguments不会自动反映函数参数的变化
不能使用arguments.callee
不能使用arguments.caller
禁止this指向全局对象
不能使用fn.caller和fn.arguments获取函数调用的堆栈
增加了保留字(比如protected、static和interface)
2、export命令 规定模块的对外接口,可出现模块的任何位置 ,必须是顶层,否则报错
语法 :export {, , ,}
也可对输出变量重命名 export {
变量 as 新起的名,
变量 as 新起的名
}
3、import命令 使用export命令定义了模块的对外接口以后,其他 JS 文件就可以通过import命令加载这个模块
语法:import(模块路径)
应用 1)按需加载
2)条件加载

语法:import {firstName, lastName,year } from ‘./profile.js’ import后面的from指定模块文件的位置,可以是相对路径,也可以是绝对路径
⚠️ 引入的变量名要与人家模块导出的名字一致,当然可以使用关键字as进行重命名 import {firstName as hhh } from ‘./profile.js’;
⚠️import命令输入的变量都是只读的,不允许在进行改写,若引入的变量是对象,对对象属性的改写是可以的 但别的模块也会相应地改写,所以禁止用
⚠️import命令具有提升效果,会提升到整个模块的头部,首先执行
⚠️由于import是静态执行,所以不能使用表达式和变量
4、export default命令,为模块指定默认输出。import命令导入时指定任意名字
⚠️与export的区别,他后面不可以跟变量的声明,但可以跟具体的数值,与export完全不同,并且它对应的导入不可有大括号
5、import()//实现动态加载功能,在运行时加载指定的模块。 会返回一个Promise对象,当加载成功,将这个模块当作then的参数传入

二十三、Module的加载实现
HTML 网页中,浏览器通过

二十四、编程风格(如何将 ES6 的新语法,运用到编码实践之中,与传统的 JavaScript 语法结合在一起,写出合理的、易于阅读和维护的代码)
1、块级作用域
1)let 取代 var 增加块级作用域,变量只在所在的块级有效 这样减少全局属性的增加及不存在变量提升
2)在let和const之间,建议优先使用const 尤其是在全局环境,不应该设置变量,只应设置常量
好处:一是阅读代码的人立刻会意识到不应该修改这个值,二是防止了无意间修改变量值所导致的错误
2、字符串。静态字符串一律使用单引号或反引号,不使用双引号。动态字符串使用反引号
就是利用模版字符串, 来拼接变量。 e g . c o n s t b = ‘ f o o {}来拼接变量。 eg.const b = `foo 来拼接变量。eg.constb=foo{a}bar`;
3、使用解构赋值
4、对象
1)单行定义的对象,最后一个成员不以逗号结尾。多行定义的对象,最后一个成员以逗号结尾
2)对象尽量静态化,一旦定义,就不得随意添加新的属性。如果添加属性不可避免,要使用Object.assign方法 Object.assign(a, { x: 3 }); 即就是a.x=3
3)对象的属性和方法,尽量采用简洁表达法. add(){} 而不是 add:function(){}
5、数组. 之前喜欢用for循坏来拷贝数组,尽量用扩展运算符去拷贝数组
使用 Array.from 方法,将类似数组的对象转为数组
6、函数
1)立即执行函数可以写成箭头函数的形式
2)简单的、单行的、不会复用的函数,建议采用箭头函数
3)使用默认值语法设置函数参数的默认值
7、Map 需要key: value的数据结构,使用 Map 结构。因为 Map 有内建的遍历机制
8、class 用它取es5中构造函数原型的写法
9、尽量开发模块化。使用import与export或export default
⚠️模块默认输出一个函数,函数名的首字母应该小写
模块默认输出一个对象,对象名的首字母应该大写

二十五、规格(详细描述语言内部语法规则和实现方法)

二十六、异步遍历器
1、同步遍历器。 之前学习的遍历器的next方法是同步的(Iterator 协议里面next()方法只能包含同步操作)
2、异步遍历器。 ES2018 引入了“异步遍历器”为异步操作提供原生的遍历器接口,即value和done这两个属性都是异步产生 即调用遍历器的next方法,返回的是一个 Promise 对象,可以使用then方法指定,
这个 Promise 对象的状态变为resolve以后的回调函数。回调函数的参数,则是一个具有value和done两个属性的对象,这个跟同步遍历器是一样的
对象的异步遍历器接口,部署在Symbol.asyncIterator属性上面。不管是什么样的对象,只要它的Symbol.asyncIterator属性有值,就表示应该对它进行异步遍历 ,
异步遍历的next方法回的是一个 Promise对象 若自己去实现的话就让next方法中返回一个Promise对象
3、具有同步遍历接口的我们可以用for of 循坏遍历。
而具有异步遍历接口的可用for await…of
4、异步 Generator 函数的作用,是返回一个异步遍历器对象,而之前学的调用 Generator 函数返回的是同步遍历器
在前面加async 此时调用next方法返回的是异步的Promide对象,可用then等方法,它的参数就是{value:,done:}
⚠️异步 Generator 函数内部,能够同时使用await和yield命令。可以这样理解,await命令用于将外部操作产生的值输入函数内部,yield命令用于将函数内部的值输出 即value属性值
5、yield*语句也可以跟一个异步遍历器。如跟一个Generator函数遍历器,否则我们还需手动去遍历

二十七、ArrayBuffer

二十八、Decorator. Decorator 提案经过了大幅修改,目前还没有定案,es6中讲的完全依据以前的提案,已经有点过时了
1)整个类的装饰
@testable
class MyTestableClass{

         // ... }
                      }  
                再通过装饰器函数可对类尽享添加改写属性等操作,函数的参数就是类本身
           2)类方法的装饰
       class MyTestableClass{
         @readonly              
          name(){ }
         // ... }
                     }  
                  装饰器函数的参数分别为类的原型对象、要装饰的属性名、该属性的描述对象

           3)core-decorators.js是一个第三方模块,提供了几个常见的装饰器

补充
https://juejin.cn/post/6844903811622912014
https://juejin.cn/post/6844904018834096142 ES7 8 9 10新特性
在这里插入图片描述
之前的看ES6第三版(2015、2016、2017)
ES9即ES2018(2018.6月发版)用时需要看浏览器支持情况

//(1) for await of:for of可以遍历具有Symbol.iterator的同步迭代数据,异步不行
function Gen (time) {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve(time)
    }, time)
  })
}
async function test () {
  let arr = [Gen(2000), Gen(100), Gen(3000)]
  for await (let item of arr) {
    console.log(Date.now(), item)
  }
// 2000 100 3000

// (2)扩展运算符的扩展 (用于对象)
{
...obj1,
c:11,
}

// (3)Promise的finally方法,Promise不管执行then/catch,finally最终会被执行
// (4)新的正则表达式特性
    s(dotAll)flag,在正则表达式中.操作符代表任意单个字符(除四字节字符(u解决)及换行回车)
    s用于支持回车\r  换行\n
    eg、、
    console.log(/foo.bar/.test('foo\nbar')) // false
    console.log(/foo.bar/s.test('foo\nbar')) // true

    命名捕获组:允许每组匹配指定的一个名字,模式的头部添加“问号 + 尖括号 + 组名”(?),可以准确拿个各个组的信息
    const re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
	const match = re.exec('2019-01-01');
	console.log(match.groups);  // → {year: "2019", month: "01", day: "01"}
	console.log(match.groups.year);     // → 2019
	console.log(match.groups.month);    // → 01
	console.log(match.groups.day);      // → 01

    后行断言:?<...是后行断言  ?...是先行断言(先行断言先判断条件再看是否满足只能判断后)
    let test = 'world hello'
    console.log(test.match(/(?<=world\s)hello/))  // hello的前面是否world 
    // ["hello", index: 6, input: "world hello", groups: undefined]
    
    
    Unicode属性转义: \p \P允许匹配符合Unicode某种属性的所有字符
    const str = '㉛';
	console.log(/\d/u.test(str));    // → false
	console.log(/\p{Number}/u.test(str));     // → true

    \p{Alphabetic}来匹配所有的Unicode单词字符
    负向的Unicode属性转义模板 \P{...}  // 例如/\P{Alphabetic}/u等,除单词字符
    console.log(/\P{Number}/u.test('㉛'));    // → false
	console.log(/\P{Number}/u.test('ض'));    // → true
	console.log(/\P{Alphabetic}/u.test('㉛'));    // → true
	console.log(/\P{Alphabetic}/u.test('ض'));    // → false

在这里插入图片描述
ES10即ES2019(2019.6月发版)

// Array.prototype.flat() 数组原型上的拉平方法,多维数组拉平
arr.flat(depth)  // depth默认1,使用 Infinity,可展开任意深度的嵌套数组,会移除空项

// Array.prototype.flatMap() // 拉平1层,传入函数,处理成自己要的结构或逻辑,返回新数组
var arr1 = [1, 2, 3, 4];
arr1.map(x => [x * 2]);// [[2], [4], [6], [8]]
arr1.flatMap(x => [x * 2]);// [2, 4, 6, 8]

// Object.fromEntries() // 与Object.entries相反使得根据entries结果可得到对象
const object = { x: 23, y:24 };
const entries = Object.entries(object); // [['x', 23], ['y', 24]]
const result = Object.fromEntries(entries); // { x: 23, y: 24 }

// String.trimStart 和 String.trimEnd 移除开头或结尾的空格(可能第一个空格)
let str = ' 前端工匠 '
console.log(str.length) // 6
str = str.trimStart()
console.log(str.length) // 5
let str1 = str.trim() // 清除前后的空格
console.log(str1.length) // 4
str.replace(/^\s+/g, '') // 也可以用正则实现开头删除空格

// String.prototype.matchAll  可以一次性取出所有的匹配,返回的是遍历器,可循环取出
function collectGroup1 (regExp, str) {
  let results = []
  for (const match of str.matchAll(regExp)) {
    results.push(match[1])
  }
  return results
}
console.log(collectGroup1(/"([^"]*)"/g, `"foo" and "bar" and "baz"`))
// ["foo", "bar", "baz"]

// try…catch,catch参数可省
// ES10之前
try {
  // tryCode
} catch (err) {
  // catchCode
}
// ES10
try {
  console.log('Foobar')
} catch {
  console.error('Bar')
}

// BigInt:js中所有的数保存成64位浮点数(16位十进制)一个字节8位无符号数 +-2^53-1,超过则无法精确表示。大于或等于2的1024次方的数值,JavaScript 无法表示,会返回Infinity
// 超过 53 个二进制位的数值,无法保持精度
Math.pow(2, 53) === Math.pow(2, 53) + 1 // true
// 超过 2 的 1024 次方的数值,无法表示
Math.pow(2, 1024) // Infinity
// 用新的数据类型大整数BigInt来解决,只能用于表示整数,任何位数都可以(创建时加上n即可)
const aNumber = 111;
const aBigInt = BigInt(aNumber);
aBigInt === 111n // true
typeof aBigInt === 'bigint' // true
typeof 111 // "number"
typeof 111n // "bigint"

// Symbol.prototype.description:获取描述
Symbol('desc').description;  // "desc"
Symbol('').description;      // ""
Symbol().description;        // undefined

// Function.prototype.toString():之前会去除空白符号,现在呈现原本源码
要求返回一模一样的函数字符串,注释空格不可以省
function sum(a, b) {
  return a + b;
}
console.log(sum.toString());
// function sum(a, b) {
//  return a + b;
// }

ES11即ES2020(2020.6月发版)

// 1、可选链操作符:?.  访问对象链深处的值,不必明确每个引用都有效,遇null、undefined短路返回undefined,先隐式检查并确定前面的不是null/undefined
obj.val?.prop
obj.val?.[expr]
obj.func?.(args)
 // 例子
let nestedProp = obj.first?.second;   // 同obj.first.second取值时兼容写法
let temp = obj.first;
let nestedProp = ((temp === null || temp === undefined) ? undefined : temp.second);

// 2、空位合并操作符 ??  如果在左侧运算为undefined、null返回右侧默认值(替换之前使用||)
let c = a ?? b;
// 等价于let c = a !== undefined && a !== null ? a : b;
// 例子:经常无值设置其他值情况会忽略false、0等正常的输入
let c = a ? a : b // 方式1
let c = a || b // 方式2 (只要a为假就是b的值,例如是空值,false,0等都直接取值b)

// 3、Promise.allSettled:并发处理多个请求,不会短路,等到全部处理完成可拿到每个Promise状态
我们知道 Promise.all 具有并发执行异步任务的能力。但它的最大问题就是如果参数中的任何一个promise为reject的话,则整个Promise.all 调用会立即终止,并返回一个reject的新的 Promise 对象。
Promise.allSettled优于Promise.all(一个异常返回则不能正确拿到)
Promise.allSettled([
  Promise.reject({ code: 500, msg: '服务异常' }),
  Promise.resolve({ code: 200, list: [] }),
  Promise.resolve({ code: 200, list: [] })
]).then(res => {
  console.log(res)
  /*
        0: {status: "rejected", reason: {…}}
        1: {status: "fulfilled", value: {…}}
        2: {status: "fulfilled", value: {…}}
    */
  // 过滤掉 rejected 状态,尽可能多的保证页面区域数据渲染
  RenderContent(
    res.filter(el => {
      return el.status !== 'rejected'
    })
  )
})

// 4、String.prototype.matchAll 匹配所有满足的,for of遍历取出

// 5、Dynamic import

// 6、globalThis:可以在任意上下问任意时刻获取全局对象(实际拿到window self global)
全局变量 window:浏览器中是一个经典的获取全局对象的方法。但是它在 Node.js 和 Web Workers 中并不能使用( Web 内容在后台线程中运行脚本提供了一种简单的方法)
全局变量 self:通常只在 Web Workers 和浏览器中生效。但是它不支持 Node.js。一些人会通过判断 self 是否存在识别代码是否运行在 Web Workers 和浏览器中
全局变量 global:只在 Node.js 中生效
// ES10之前的解决方案
const getGlobal = function(){
  if(typeof self !== 'undefined') return self
  if(typeof window !== 'undefined') return window
  if(typeof global !== 'undefined') return global
  throw new Error('unable to locate global object')
}
// ES10内置
globalThis.Array(0,1,2) // [0,1,2]
// 定义一个全局对象v = { value:true } ,ES10用如下方式定义
globalThis.v = { value:true }
Object.prototype.isPrototypeOf(globalThis); // true
// 7、大整数计算问题
BigInt(Math.pow(2, 53)) === BigInt(Math.pow(2, 53)) + BigInt(1)

在这里插入图片描述

ES12即ES2021(2021.6月发版)

// 1、String.prototype.replaceAll 全部替换,无需使用正则的g
const queryString = 'q=query+string+parameters';
const withSpaces = queryString.replace(/+/g, ' '); // +用空格替换
const withSpaces = queryString.replaceAll('+', ' ');

// 2、Promise.any 
这个可以和之前的 Promise.race 进行比较,二者都有短路原则,Promise.race 会在某一个 Promise 被解决的时候完成,而 Promise.any 会在某一个 Promise 处于 fulfilled 态的时候完成。有点绕,还是举例子:
Promise.race([promise1, promise2]).then(res => {
  console.log(res)
}, (error) => {
  console.error(error)
})

Promise.any([promise1, promise2]).then(res => {
  console.log('我没有错误')
  console.log(res)
}, (error) => {
  console.error(error)
})

// 3、逻辑赋值操作符 
x &&= y  // 相当于 x && (x = y) 如果 x 为真,则将 y 的值赋给 x
x ||= y  // 相当于 x || (x = y)  如果x为假则将y值赋值给x
x ??= y  // 相当于 x ?? (x = y)  ??空值合并操作符

// 4、数字分隔符:数字有了更方便的书写方式(使用“_”来实现数字可读性),也可以直接参与运算
const a = 1_000  // 1000
const b = 1_000_000  // 1000000

ES13即ES2022(2022.6月发版)

// 1、 Object.hasOwn 判断属性在不在对象自身中, 属性 in 对象(对象及原型上判断) obj.hasOwnProperty(‘名称’)(只在对象属性找)
// 2、.at() 取数组索引处值,支持负数表示倒数第一个来找数组元素
var a = [1, 2, 3];
a.at(1) // 2
a.at(-1) // 3

// 3、可以在模块的顶层使用 await 支持全局作用链异步加载(无需在async函数中)
let jQuery;
try {
  jQuery = await import('https://cdn-a.com/jQuery');
} catch {
  jQuery = await import('https://cdn-b.com/jQuery');
}

// 4、 类的成员变量:私有变量、私有方法、静态私有变量、静态私有方法
设置私有属性的方式是在变量前面加一个修饰符 #
class ClassWithPrivateProperty {
  #privateField;
  static #PRIVATE_STATIC_FIELD;
  constructor() {
    this.#privateField = 42;
  }
  #privateMethod() {
    return 'hello world';
  }
  static #privateStaticMethod() {
    return 'hello world';
  }
}
// 5、RegExp Match Indices   正则表达式匹配指数 d修饰符

// 6、in:支持使用in判断私有属性在 对象里是否存在

// 7、Class Static Block 类静态模块

ES14即ES2023(2023.6月发版)

// 1、数组新增方法
toSorted、toReversed、toSpliced同原来的方法sort、reverse、splice方法,不过不会修改原数组会返回新的数组
with:更改给定索引值的复制版本(不会修改原数组,返回更改后的新数组) array.with(1, 'fatfish')索引1处值改为fatfish
findLast、findLastIndex:从后往前找符合条件的元素,找到结束返回找到的值或索引
// WeakMap 弱引用 
WeakMap:支持使用Symbol作为key(之前只能使用object作为key)