添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
ES7~ES12新特性基础笔记整理

ES7~ES12新特性基础笔记整理

ES7,Array.prototype.includes

>>>>>includes方法是用来检测数组中是否包含某个元素,返回相对应得布尔类型值

  • 跟indeOf()方法有点类似
let school = ['清华大学','北京大学','浙江大学'];
console.log(school.includes('清华大学'));     // true






ES7,求幂运算(**)

>>>>>类似方法:1.自定义递归函数,2.Math.pow()方法

let num01 = Math.pow(2,10); //Math.pow()方法
let num02 = 2 ** 10; // 幂运算(**)
console.log(num01,num02); // 1024,1024








ES8,async函数,await表达式

(ES8async函数)

>>>>>Async 和 Awaiit 是 Promise 的扩展,JavaScript 是单线程的,使用 Promise 之后可以使异步操作的书写更简洁,而 Async 使 Promise 像同步操作。

async函数的返回值是Pormise对象
Promise对象的结果由async函数执行的返回值所决定
// 在申明函数的前面加"async"
async function test() {
	// 只要返回的不是一个Promise类型对象,则返回的结果是成功的Promise对象的,哪怕只有“return”
	return 'javascript';
	throw new Error('error');


  • 如果返回的是一个Promise对象
// 在申明函数的前面加"async"
async function test() {
	return new Promise((resolve,reject) => {
	// Promise对象的状态由函数内部return语句决定,即由resolve和reject的最终结果所决定
		resolve('success!');
		reject('errro!');
  • 这时候调用then()方法
// 在申明函数的前面加"async"
async function test() {
	return new Promise((resolve,reject) => {
		 //resolve('success!');
		reject('errro!');
test().then(value => {
	console.log(value);  //如果状态为resolve则异步返回value
},reason => {
	console.warn(reason); //如果状态为reject则异步返回value

(ES8await表达式)

>>>>>Await 放置在 Promise 调用之前,强制后面的代码等待,直到 Promise 对象 resolve,得到 resolve 的值作为 await 表达式的运算结果

await必须写在async函数中
await右侧的表达式一般为Promise对象
await返回的是Promise成功的值
await的Promise失败了,则会抛出异常,需要通过try-catch捕获结果
  • 成功的值
let pro = new Promise((resolve,reject) => {
	resolve('接受!');
async function test() {
	let result = await pro;
console.log(result);  // 返回的就是Promise成功的值
test();
  • 失败的值(用try-catch捕获结果)
let pro = new Promise((resolve,reject) => {
	reject('失败!');
async function test() {
	try {
		let result02 = await pro;
		console.log(result02);  //失败!
	} catch(e) {
		console.log(e);
test();





(ES8async函数与await表达式结合运用)

在根目录创建3个文本文件
// 单独写在js文件中,用终端直接运行
let fs = require('fs');
function readFile01() {
	return new Promise((resolve,reject) => {
		fs.readFile('./11.txt',(err,data) => {
			if(err) reject(err);
			resolve(data);
function readFile02() {
	return new Promise((resolve,reject) => {
		fs.readFile('./22.txt',(err,data) => {
			if(err) reject(err);
			resolve(data);
function readFile03() {
	return new Promise((resolve,reject) => {
		fs.readFile('./33.txt',(err,data) => {
			if(err) reject(err);
			resolve(data);
async function result() {
	let read01 = await readFile01();
	let read02 = await readFile02();
	let read03 = await readFile03();
	console.log(read01 + '\r');
	console.log(read02 + '\r');
	console.log(read03 + '\r');
result();
终端结果
  • 两者结合发送Ajax请求
// 使用ES6 Promise的then方法
// 发送get请求,返回Promise对象
function XML(url) {
	let x = new XMLHttpRequest();				
	return new Promise((resolve,reject) => {
		x.open('get',url);
		x.send();
		x.onreadystatechange = () => {
			if(x.readyState === 4) {
				if(x.status >= 200 < 300) {
					resolve(x.response);		
				}else {
					reject(x.status);
let result = XML('./22.txt').then(value => {
	console.log(value);  // (控制台输出文本结果)
},reason => {


// 使用async和await结合使用
// 发送get请求,返回Promise对象
function XML(url) {
	let x = new XMLHttpRequest();			
	return new Promise((resolve,reject) => {
		x.open('get',url);
		x.send();
		x.onreadystatechange = () => {
			if(x.readyState === 4) {
				if(x.status >= 200 < 300) {
					resolve(x.response);	
				}else {
					reject(x.status);
async function result() {
	let result = await XML('./22.txt');
	console.log(result);
result(); // (控制台输出文本结果)








ES8,对象方法扩展

>>>>>包含【Object.value、Object.entries、Object.getOwnPropertyDescriptors】

//---
let school = {
	name:'TsingHua',
	subject:['math','chinese']
// 获取对象所有的键值
console.log(Object.keys(school));  // ['name', 'subject']
console.log(Object.values(school));  //   ['TsingHua', Array(2)]
console.log(Object.entries(school));  //  [Array(2), Array(2)]
// 方便创建Map
let result = new Map(Object.entries(school));
console.log(result.get('subject'));  // Object.entries返回的是一个数组['math','chinese']

Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致 。

Object.values() 方法返回一个给定对象自身的所有可枚举属性值的数组,值的顺序与使用for-in循环的顺序相同 ( 区别在于 for-in 循环枚举原型链中的属性 )。

// getOwnPropertyDescriptors返回的是对象属性的描述对象
console.log(Object.getOwnPropertyDescriptors(school));
返回的是一个对象,里面也有键有值


展开这个对象,会看到键对应的值不一样,是因为Object.Create创建对象时属性描述对象的一个结构
// Object.getOwnPropertyDescriptors()返回的就是以下对象,可以更深层次地对对象进行克隆
let obj = Object.create(null, {
	name:{
		value:'TsingHua',
		writable:true,
		configurable:true,




ES9,扩展运算符和Rest参数

>>>>>Rest参数与spread扩展运算符在ES6中已经加入到原生js里面,但是ES6中只针对于数组,在ES9中它们也支持对象

// Rest参数语法允许我们将一个剩余参数表示为一个数组
function foo(a, b, ...rest) {
  return [a,b,...rest];
let result = foo(1, 2, 3, 4, 5);
console.log(result); //[1, 2, 3, 4, 5]


// ES9的Rest参数支持对象
let university01 = {
	name:'清华大学',
let university02 = {
	address:'BeiJing',
let university03 = {
	subject:'ComputerScience'
let result = {...university01,...university02,...university03};
console.log(result);  //{name: '清华大学', address: 'BeiJing', subject: 'ComputerScience'}
跟数组一样,Rest参数只能在声明的结尾处使用
展开操作符则是将数组转换成可传递给函数的单独参数






ES9,正则扩展,命名捕获分组

正则扩展,命名捕获分组---分组匹配到的结果进行命名,对结果进行处理>>>>>

// 没有进行命名捕获分组的处理
//声明一个字符串
let Link = ' <a href="https://www.baidu.com">百度</a>';
//我们可以提取Link字符串中的网址以及标签里面的文本信息
let reg01 = /<a href = "(.*)">(.*)<\/a>/;
let result01 = reg01.exec(Link01);
console.log(result01);
控制台截图
  • 第0个元素是正则整个匹配到的结果
    第1个元素是正则是第一个“(.*)”匹配到的结果
    第2个元素是正则是第一个“(.*)”匹配到的结果
    其中2和3都可以称为捕获>>>得到如下结果
console.log(result01[1]);   //https://www.baidu.com
console.log(result01[2]);   //百度

------------------------------------------分割线--------------------------------------------

//  运用分组 
let Link02 = '<a href="https://www.baidu.com"></a>';
// -----规定语法-----
//在未运用分组的基础上,在需要捕获的括号内部添加 “?<捕获标识符>.*”
let reg02 = /<a href="(?<url>.*)">(?<text>.*)<\/a>/
const result02 = reg02.exec(Link02);
console.log(result02.groups.url);
控制台截图
  • 上面的0、1、2都还在,在“groups”中多了上面运用分组所捕获的数据
console.log(result02.groups.url);  //https://www.baidu.com
console.log(result02.groups.text); //百度

这样一来我们提取正则所捕获的数据会更加地方便和便于维护





ES9,正则扩展,反向断言

反向断言,用于判断匹配结果是否正确

// 先使用正向断言
// 提取 “TsinghuaUniversity2030”
let content = '清华大学TsinghuaUniversity2030级';
// 正向断言
let regExctart = /\w+(?=级)/;
let result = regExctart.exec(content);
console.log(result[0]);  //TsinghuaUniversity2030
捕获到的结果就是“级”前面的字符串
// 再使用反向断言
// 提取 “TsinghuaUniversity2030”
let content = '清华大学TsinghuaUniversity2030级';
// 反向断言
let regExctart = /(?<=学)\w+/;
let result = regExctart.exec(content);
console.log(result[0]);  //TsinghuaUniversity2030
结果是与正向断言结果一致






ES9,正则扩展,dotAll模式

JavaScript正则表达式中点(.)是一个特殊字符,它可以匹配除了一下条件的任意字符。

四个字节的UTF-16字符
换行符(\n)
回车符(\r)
行分隔符
段分隔符

为了使点(.)可以匹配任意字符,ES2018引入新的修饰符s。这种模式被称为dotAll模式,根据字面意思便是dot(.)匹配一切字符。


 const re = /foo.bar/s
// 判断是否启用dotAll模式
console.log(re.dotAll) // true
正则表达式中,点(.)是一个特殊字符,代表除了换行符以外的任意单个字符。
 <ul>
	      <a>JavaScript数据结构</a>
	      <p>出版日期2020-10-24</p>
	      <a>JavaScript算法</a>
	      <p>出版日期2021-10-24</p>
往常的做法在捕捉的时候要把多余的空格添加上去
dot正好可以更方便的处理这个问题
let reg = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/gs;
let result;
while(result = reg.exec(bookStr)) {
    console.log(result);
提取内容的话也非常方便
let data = []; //定义一个数组
while(result = reg.exec(bookStr)) {
     data.push(result[1],result[2])
console.log(data);
提取内容的话也非常方便






ES10,对象扩展方法Object.fromEntries

Object.fromEntries()方法把键值对列表转换为一个对象,该方法创建对象,参数接收二维数组和Map>>>>>

// 定义一个二维数组
let content = Object.fromEntries([
	['name', 'javascript算法'],
	['data', '2021-10-24']
console.log(content);


// 定义一个Map对象
let mapObj = new Map();
// 传入参数
mapObj.set('name', 'javascript算法');
let result = Object.fromEntries(mapObj);
console.log(result);
控制台结果
  • 用回ES8的Object.entries方法
let arr = Object.entries({
	name: 'javascipt算法'
console.log(arr);
控制台结果


entries()方法可以把对象转化为数组,Object.fromEntries则把二维数组转化为对象

>>>>>Object.fromEntries和ES8里面的entries()方法为相互的逆运算(互逆)






ES10,字符串扩展方法【trimStart,trimEnd】

trimStart、trimEnd可以清楚多余的空白>>>>>

//声明一个字符串
let arr = '     JavaScript     ';  //前后都有空白
console.log(arr);
未清除状态
console.log(arr.trimStart());  //清楚前面的空白
清楚前面的空白
console.log(arr.trimEnd());  //清楚后面的空白
清楚后面的空白

>>>>>trimStart清除左侧空白,trimEnd清楚右侧空白





ES10,数组方法扩展flat、flatMap

flat()方法可以将多维数组展平成一维数组>>>>>

let arrFlat01 = [1,2,3,[4,5,6]];
console.log(arrFlat01.flat()); //[1, 2, 3, 4, 5, 6]

flat()里面传递的参数为数字,数组的深度

let arrFlat02 = [1,2,3,[4,5,6,[7,8,9]]]; //仅要一层深度
console.log(arrFlat02.flat(1));  // [1, 2, 3, 4, 5, 6, Array(3)]---Array(3)包含就是数组[7,8,9]
let arrFlat03 = [1,2,3,[4,5,6,[7,8,9]]];  //需要两层深度
console.log(arrFlat03.flat(2));  //[1, 2, 3, 4, 5, 6, 7, 8, 9]


>>>flatMap()方法把原来的数组处理后返回一个新的一维数组。首先使用映射函数映射每个元素,用数组包裹起来,然后将结果压缩成一个新数组。它与map连着深度值为1的flat几乎相同, 但是flatMap通常在合并成一种方法的效率稍微高一些 >>>

  • map()和flatMap()示例
let content = [1,2,3,4,5,6];
let result = content.map(item => [item * 10]);
console.log(result);
map()示例
  • 这个时候如果想把上面的map()示例结果变成一维数组来使用,可以使用flatMap()
let content = [1,2,3,4,5,6];
let result = content.flatMap(item => [item * 10]);
console.log(result);
flatMap()示例




ES10,Symbol.prototype.description

description是一个只读属性,它会返回Symbol对象的可描述的字符串>>>>>>

let content = Symbol('清华大学');
let result = content.description;
console.log(result);   //清华大学






ES11,私有属性

私有属性只允许在类的内部调用,且不允许在在类中。私有属性通过 # 申明

class School {
	// 定义公有属性
	name;
	// 定义私有属性
	income;
	constructor(name, income) {
		this.name = name;
		this.#income = income;
let TsingHua = new School('清华大学', '1w');
console.log(TsingHua); // School{name: '清华大学', #income: '1w'}
//打印输入#incom这个私有属性
console.log(TsingHua.#income); //Private field '#income' must be declared in an enclosing class.
私有属性是无法访问得到的,在类的外部访问不到私有属性
// 我们要在class的外部进行定义
intro() {
	    console.log(this.#income);
// 调用
TsingHua.intro();  // 1w




ES11,Promise.allSettled方法

Promise.allSettled方法返回一个在所有给定的promise都已经fulfilled或reject后的promise,并带有一个对象数组,每个对象表示对应的promise结果>>>>>

let content = new Promise((resolve, reject) => {
	setTimeout(() => {
		resolve('内容一');
let content02 = new Promise((resolve, reject) => {
	setTimeout(() => {
		reject('内容一');
Promise.allSettled()返回的结果始终是成功的


// 调用 Promise.all()方法
let result = Promise.all([content, content02]);
console.log(result);
Promise.all()方法,只要有一失败则直接返回失败
按使用场景来区分:
如果想每个异步任务都想得到同一个结果,使用Promise.allSettled方法
如果想每个异步任务要求每个都成功才能够继续往下执行,使用Promise.all()方法




ES11,String.prototype.matchAll()方法

>>>>>String.prototype.matchAll()方法,用来得到正则批量匹配得到的结果

// String.prototype.matchAll()方法
let str =
			<a>《JavaScript数据结构》</a>
			<p>出版日期:2020-10-24</p>
			<a>《JavaScript算法》</a>
			<p>出版日期:2021-10-24</p>
		</ul>`;
let reg = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/sg;
let result = str.matchAll(reg);
console.log(result);
从“next”可看出返回的结果是可迭代对象


// 运用for-of进行遍历得到结果
for (let i of result) {
	console.log(i);
// 运用扩展运算符得到结果
let arr = [...result];
console.log(arr);
得到了整体匹配的结果





ES11,可选链操作符

可选链操作符--->(?.)的组合,允许读取位于连接对象链深处的属性的值,即可读取对象类型的参数,短路返回值是undefined,且与函数调用一起使用时,如果给定的函数不存在,则返回undefined>>>>>

function language(content) {
	let useLauguage = content && content.one.Good && content.one.purpose;
	//可以获取到对应的值
	console.log(useLauguage);
language({
	one: {
		Good: 'javascript',
		purpose: 'HTML'
	tow: {
		Good: 'c++',
		purpose: 'app'
function language(content) {
// 注释原来的条件判断,直接获取
// let useLauguage = content && content.one.Good && content.one.purpose;
	let useLauguage = content.one.Good;
	console.log(useLauguage);
//直接调用报错:Cannot read properties of undefined (reading 'one').
language();
// language({
// 	one:{
// 		Good:'javascript',
// 		purpose:'HTML'
// 	},
// 	tow:{
// 		Good:'c++',
// 		purpose:'app'
// 	}
// })
  • 运用可选链操作符
function language(content) {
	let useLauguage = content?.one;
	console.log(useLauguage);
language({
	one:{
		Good:'javascript',
		purpose:'HTML'
	tow:{
		Good:'c++',
		purpose:'app'
正常获取
// 
function language(content) {
	let useLauguage = content?.one;
	console.log(useLauguage);
// 就算直接调用也不会报错,控制台显示undefined
language();




ES11,动态import

在此之前,我们都是使用静态的import引入页面中所需要的功能模块。动态import的作用就算按需要来加载需要引入的功能模块>>>>>


1.首先在主页部分创建一个按钮实现点击按钮弹出提示框

//HTML部分
<!DOCTYPE html>
		<meta charset="utf-8">
		<title></title>
		<script src="app.js" type="module" charset="utf-8"></script>
	</head>
		<button type="button" id="btn">我是一个按钮</button>
	</body>
</html>

2.运用动态import直接调用已经声明且暴露的函数(直接输出传入的“module”)

// app.js部分
let btn = document.getElementById('btn');
btn.onclick = () => {
	// 动态import
	import('./module01.js').then(module => {
		module.hello();

3.声明暴露函数

// module.js部分
export function hello() {
	alert('Hello!!!!!!');


//动态引入import()变量失效问题
//webpack的现在的实现方式不能实现完全动态,所以可以通过字符串模板来提供部分信息给webpack
const modelpath = '/demo';
import(`@/pages${modelpath}`).then(item => {})




ES11,BigInt类型

BinInt是一种内置对象,它提供了一种方法表示大于2的53次方-1的整数。这原本是Javascript中可以用Number表示的最大数字。BigInt可以表示任意大的整数>>>>>

// 在一个整数字面量后面加“n”的方式定义一个BigInt
let num = 10n;
console.log(num);  //10n
console.log(typeof num);  //bigint


// 不支持浮点类型的数字
let num = 10.1n;
console.log(num);  //Invalid or unexpected token


// 函数形式
let num = BigInt(10);
console.log(num);  //10n
console.log(typeof num);  //bigint
大数值运算---对比Javascript最大安全整数计算Number.MAX_SAFEE_INTEGER
// 超出Number.MAX_SAFE_INtEGER会出现问题
let maxNum = Number.MAX_SAFE_INTEGER;
console.log(maxNum);  //9007199254740991
console.log(maxNum + 1);  //9007199254740992
console.log(maxNum + 2);  //9007199254740992
console.log(maxNum + 3);  //9007199254740993
console.log(maxNum + 4);  //9007199254740996


// 用BigInt
let maxNum = Number.MAX_SAFE_INTEGER;
console.log(BigInt(maxNum));  //9007199254740991n
console.log(BigInt(maxNum) + BigInt(1));  //9007199254740992n
console.log(BigInt(maxNum) + BigInt(2));  //9007199254740993n
console.log(BigInt(maxNum) + BigInt(3));  //9007199254740994n
console.log(BigInt(maxNum) + BigInt(4));  //9007199254740995n

>>>>>>由于在Number与BigInt之间进行转换会损失精度,因此建议仅在值大于2的53次方时shi用BigInt类型,并且不在这两种类型之间进行想换转换







ES11,globalThis

globalThis包含全局的this值,类似于全局对象global object>>>>>

在以前,从不同的 JavaScript 环境中获取全局对象需要不同的语句。在 Web 中,可以通过 window self 或者 frames 取到全局对象,但是在 Web Workers 中,只有 self 可以。在 Node.js 中,它们都无法获取,必须使用 global

在松散模式下,可以在函数中返回 this 来获取全局对象,但是在严格模式和模块环境下, this 会返回 undefined 。 You can also use Function('return this')() , but environments that disable eval() , like CSP in browsers, prevent use of Function in this way.

globalThis 提供了一个标准的方式来获取不同环境下的全局 this 对象(也就是全局对象自身)。不像 window 或者 self 这些属性,它确保可以在有无窗口的各种环境下正常工作。所以,你可以安心的使用 globalThis ,不必担心它的运行环境。为便于记忆,你只需要记住,全局作用域中的 this 就是 globalThis

>>>>>简言之,如果说想对全局对象进行操作,可以直接忽略环境直接使用globalThis,就可以指向全局对象


HTML文件输出控制台


使用Node.js运行index.js








ES12, String.prototype.replaceAll--- replaceAll()

  • >>>>> replaceAll()返回一个全新的字符串,所有符合匹配规则的字符都将被替换掉,替换规则可以是字符串或者正则表达式。
  • 而replace()只能是替换字符串中匹配到的第一个实例字符,而不能进行全局多项匹配替换,唯一的办法是通过正则表达式进行相关规则匹配替换。
// replaceAll() 方法
let str = 'Java是世界上最好的编程语言!Java爱了爱了!';
let transformStr = str.replaceAll('Java','JavaScript');
console.log(transformStr); //JavaScript是世界上最好的编程语言!JavaScript爱了爱了!
// replace() 方法
let str02 = 'Java是世界上最好的编程语言!Java爱了爱了!';
let transformStr02 = str.replace('Java','JavaScript');
console.log(transformStr02); //JavaScript是世界上最好的编程语言!Java爱了爱了!


//注意,replaceAll在使用正则表达式的时候,如果非全局匹配(/g),则replaceAll()会抛出一个异常
let str = 'Java是世界上最好的编程语言!Java爱了爱了!';
console.log(str.replaceAll(/Java/,'JavaScript')); //TypeError







ES12,Promise.any

  • >>>>>当Promise列表中的任意一个promise成功resolve则返回第一个resolve的结果状态
  • 如果所有的promise均reject,则抛出异常表示所有请求失败
Promise.any([
new Promise((resolve, reject) => setTimeout(reject, 500, 'Java是世界上最好的编程语言!')),
new Promise((resolve, reject) => setTimeout(resolve, 1000, 'JavaScript是世界上最好的编程语言!')),
new Promise((resolve, reject) => setTimeout(resolve, 2000, 'Php是世界上最好的编程语言!')),
.then(value => console.log(value))  // JavaScript是世界上最好的编程语言!
.catch (err => console.log(err));


//还有这种情况
Promise.any([
	Promise.reject('Error 1'),
	Promise.reject('Error 2'),
	Promise.reject('Error 3')
.then(value => console.log(value))
.catch (err => console.log(err))
//输出AggregateError: All promises were rejected
Promise.any与Promise.race十分容易混淆,务必注意区分,Promise.race 一旦某个promise触发了resolve或者reject,就直接返回了该状态结果,并不在乎其成功或者失败






ES12,WeakRefs

  • >>>>>使用WeakRefs的Class类创建对对象的弱引用(对对象的弱引用是指当该对象应该被GC回收时不会阻止GC的回收行为)
  • 当我们通过(const、let、var)创建一个变量时,垃圾收集器GC将永远不会从内存中删除该变量,只要它的引用仍然存在可访问。WeakRef对象包含对对象的弱引用。对对象的弱引用是不会阻止垃圾收集器GC恢复该对象的引用,则GC可以在任何时候删除它。
  • WeakRefs在很多情况下都很有用,比如使用Map对象来实现具有很多需要大量内存的键值缓存,在这种情况下最方便的就是尽快释放键值对占用的内存。
  • 目前,可以通过WeakMap()或者WeakSet()来使用WeakRefs
let map = new Map();
function doSomething(obj) {
	return obj;
function useObject(obj) {
	doSomething(obj);
	let called = map.get(obj) || 0;
	called++;
	if (called > 1000) {
		console.log('当前调用次数已经超过1000次了');
	map.set(obj, called);
以上虽然可以实现我们的功能,但是会发生内存溢出,因为传递给doSomething函数的每个对象都永久保存在map中,并且不会被GC回收,因此我们可以使用WeakMap
因为是弱引用,所以WeakMap、WeakSet的键值对是不可枚举的
WeakSet和WeakMap相似,但是每个对象在WeakSet中的每个对象只可能出现一次,WeakSet中所有对象都是唯一的


let ws = new WeakSet();
let foo = {}
let bar = {}
ws.add(foo);
ws.add(bar);
ws.has(foo); //true
ws.has(bar); //true
ws.delete(foo); //删除foo对象
ws.has(foo); //false 已删除
ws.has(bar); //仍存在


WeakSet与Set相比有以下两个区别
WeakSet只能是对象集合,而不能是任何类型的任意值
WeakSet弱引用,集合中对象引用为弱引用,如果没有其他对WeakSet对象的引用,则会被GC回收
最后,WeakRef实例有一个方法deref,返回引用的原始对象,如果原始对象被回收,则返回undefined
let cache = new Map();
let setValue = (key, obj) => {
	cache.set(key, new WeakRef(obj));
let getValue = (key) => {
	const ref = cache.get(key);
	if (ref) {
		return ref.deref();
let fibonacciCached = (number) => {
	let cached = getValue(number);
	if (cached) return cached;
	let sum = calculateFibonacci(number);
	setValue(number, sum);
	return sum;

对于缓存远程数据来说,这可能不是一个好主意,因为远程数据可能会不可预测地从内存中删除。在这种情况下,最好使用LRU之类的缓存>>>>>









ES12,逻辑运算符和赋值表达式

逻辑运算符和赋值表达式,新特性结合了逻辑运算符(&&,||,??)和赋值表达式而JavaScript已存在的
复合赋值运算符有:操作运算符:+= -= *= /= %= **=
位操作运算符:&= ^= |=
按位运算符:<<= >>= >>>=
//表达式:a op= b
//等同于:a = a op b


//表达式:a op= b
//等同于:a = a op (a = b)
//a ||= b
//等价于
//a = a || (a = b)
//a &&= b
//等价于
//a = a && (a = b)
//a ??= b
//等价于
//a = a ?? (a = b)	
//为什么不再是跟以前的运算公式a = a op b一样呢,而是采用a = a op (a = b)。因为后者当且仅当a的值为false的时候才计算赋值,只有在必要的时候才执行分配,而前者的表达式总是执行赋值操作



//??=可用来补充/初始化缺失的属性
let school = [{
		name: '清华大学',
		subject: '/'
		subject: '/other'
for (let schoolName of school) {
	schoolName.name ??= '默认排名';
console.table(school)
//(index) title path
//0 "主会场" "/"
//1 "默认标题" "/other


&&=:当LHS值存在时,将RHS变量赋值给LHS
||=:当LHS值不存在时,将RHS变量赋值给LHS
??= :当LHS值为null或者undefined时,将RHS变量赋值给LHS >>>>>









ES12,数字分隔符

>>>>>数字分隔符,可以在数字之间创建可视化分隔符,通过_下划线来分割数字,使数字更具可读性

let money01 = 1_000_000_000;
//等价于
let money02 = 1000000000;
let totalFee01 = 1000.12_34;
//等价于
let totalFee02 = 1000.1234;
//同样支持在八进制数中使用
let num01 = 0o123_456
//等价于