ES2020 (ES11)是 ECMAScript 对应 2020 年的版本。这个版本不像 ES6 (ES2015)那样包含大量新特性。但也添加了许多有趣且有用的特性。本文以简单的代码示例来介绍 ES2020新特性。这样,你能够很快理解这些新功能,而不须要多么复杂的解释,好了,废话很少说咱们进入正文🔛php
类的主要做用之一是将咱们的代码包含在可重用的模块中。因此会在许多不一样地方使用到同一个类,可是又的类里面的一些属性,为了安全或者是其余的目的,不想让其余的类可以去访问他,修改他,只能他本身用,对于一些学过c#,java等语言的同窗来讲是比较好理解的,就是 Private
一个访问修饰符,那么在咱们的js当中该怎么办了,css
别担忧,他们有的咱js也有,在ES11中也为咱们提供了私有变量,经过在变量或函数前面添加一个哈希符号#
,能够将它们设为私有属性,只在类内部可用。html
这是咱们普通的一个类前端
class Money{
constructor(money){
this.money=money;
}
}
let RMB=new Money(999);
RMB.money=999999;//这还了得,怎么能够随便改钱的金额呢
console.log(RMB.money);//能够经过对象的形式去访问
复制代码
因为安全,咱们不能让其余的类来随便更改咱们类里面的属性的值,咱们可使用 私有属性,是只能在类里面进行访问java
class Money{
#money=0;//声明这个属性是私有属性
constructor(money){
this.#money=money;
}
}
let RMB=new Money(999);
//RMB.#money=999999;//Uncaught SyntaxError: Private field '#money' must be declared in an enclosing class,
console.log(RMB.#money);//Uncaught SyntaxError: Private field '#money' must be declared in an enclosing class
复制代码
上面的代码报错了,哭唧唧,拿不到私有属性的值了,怎么办??node
我须要使用我类里面的钱,怎么获取webpack
咱们能够在类里面写两个方法,取数据,写入数据,能够进行修改,可是你不能任意改,必须经过个人方法去改,咱们能够看看下面的代码web
class Money{
#money=0;//声明这个属性是私有属性
constructor(money){
this.#money=money;
}
getMoney(){//获取值
return this.#money;
}
setMoney(money){//写入值
this.#money+=money;
}
}
let RMB=new Money(999);
RMB.setMoney(8848)
console.log(RMB.getMoney());
复制代码
好了,私有变量(属性),咱们就说到这里了,下面咱们来看看空值合并运算符吧!chrome
在咱们日常的工做中,在取一个对象里面的属性,若是这个属性没有值,咱们会这样给他一个默认值npm
let user={
name:'Symbol卢',
age:18
}
console.log(user.name,"name")//Symbol卢 name
console.log(user.like,"like")//undefined "like"
//对象里面没有这个属性的时候,他一个默认值
console.log(user.like || '写代码',"like2")//写代码 like2
复制代码
//ES2020 的?? 空值合并操做符
console.log(user.sex??'男',"sex"); //男 sex
//不存在这个sex属性,就会走后面的默认值,若是存在这个sex属性,就不会走后面的默认值
复制代码
**空值合并运算符(*??*)**是一个逻辑运算符。当左侧操做数为 null 或 undefined 时,其返回右侧的操做数。不然返回左侧的操做数。
??和 || 的区别是什么呢??
他们两个最大的区别就是 ' '和 0,??的左侧 为 ' '或者为 0 的时候,依然会返回左侧的值;
|| 会对左侧的数据进行boolean类型转换,因此' '和 0 会被转换成false,返回右侧的值
减小访问深层对象时判断属性存不存在的问题。
const a = {};
console.log(a.b.c); // 这里会报Err, 没法从undefined中获得c
console.log(person?.profile?.name); // ""
console.log(person?.hobby?.work); // undefined
console.log(person?.hobby?.work ?? "no Work"); // no Work
复制代码
可选链中的 ?
表示若是问号左边表达式有值, 就会继续查询问号后面的字段。根据上面能够看出,用可选链能够大量简化相似繁琐的前置校验操做,并且更安全。
注意:?. 不能用来赋值。
赋值,咱们一般采用 可选链操做符
和 空值合并运算符
进行搭配使用
let user={
name:'Symbol卢',
age:18,
skill:{
Web:{
html:'50%',
css:'60%',
js:'80%'
},
Server:{
node:'80%',
php:'50%',
net:'60%'
}
}
}
console.log(user.name,"name")//Symbol卢 name
console.log(user.like,"like")//undefined "like"
//咱们日常的工做中,会这样使用,当咱们的对象里面没有这个属性的时候,这样给他一个默认值
console.log(user.like || '写代码',"like2")//写代码 like2
//ES2020 的??
console.log(user.sex??'男',"sex"); //不存在这个sex属性,就会走后面的默认值,若是存在这个sex属性,就不会走后面的默认值
console.log(user.skill.Web.js,"js")//80% js
//console.log(user.skill.Database.MySql,"MySql")//Uncaught TypeError: Cannot read property 'MySql' of undefined
//空值合并运算符 与 可选链 相结合,能够很轻松处理多级查询并赋予默认值问题
console.log(user?.skill?.Database?.MySql ?? '88%',"MySql")
复制代码
关于js的浮点数的一个精度问题,最典型的就是 0.1+0.2!= 0.3
console.log(0.1+0.2,'0.1+0.2')//0.30000000000000004 "0.1+0.2"
console.log(0.1+0.2==0.3,"0.1+0.2==0.3")//false "0.1+0.2==0.3"
复制代码
JavaScript能够处理的最大数字是2 ^ 53,经过MAX_SAFE_INTEGER能够查出这个值:
JavaScript 中 Number
类型只能安全的表示-(2^53 -1)
至 2^53 -1
范的值,即 Number.MIN_SAFE_INTEGER
至 Number.MAX_SAFE_INTEGER
,超出这个范围的整数计算或者表示会丢失精度。
let maxNum=Number.MAX_SAFE_INTEGER;
console.log(maxNum)//9007199254740991
let num1=Number.MAX_SAFE_INTEGER+1;
let num2=Number.MAX_SAFE_INTEGER+2;
console.log(num1==num2,"num1==num2")//true 超过这个范围,就精度丢失了
复制代码
为解决此问题,ES2020 提供一种新的数据类型:BigInt
。使用 BigInt
有两种方式:
n
。
let bigIntNum1=9007199254740999n;
console.log(typeof bigIntNum1)//bigint
复制代码
BigInt
函数。
let bigIntNum2=BigInt(90071992547409999);
console.log(typeof bigIntNum2)//bigint
复制代码
接下来咱们再对两位数进行判断:
console.log(bigIntNum1==bigIntNum2)//false
//已结解决了以前超过这个精度不能进行计算的问题
复制代码
咱们再经过 BigInt
, 咱们能够安全的进行大数整型计算。
let BigNum=bigIntNum1+bigIntNum2;
console.log(BigNum.toString())//99079191802150999
复制代码
注意:
BigInt
是一种新的数据原始(primitive)类型。注意标准数字与
BigInt
数字不能混合使用。
typeof 9007199254740993n; // -> 'bigint'
复制代码
BigInt
方式来实例化超大整型。由于参数的字面量实际也是
Number
类型的一次实例化,超出安全范围的数字,可能会引发精度丢失。
在项目中,某些功能可能不多使用,而导入全部依赖项可能只是浪费资源。如今可使用async / await
在须要时动态导入依赖项,能够在初始化的时候不所有加载逻辑资源,只进行按需加载,这样可让首屏的渲染速度更快,虽然咱们的前端工程化项目使用的webpack已经很好支持了按需导入,可是如今可以在2020正式的进入ES的规范,咱们的js也是愈来愈强大了。
demo.js 导出模块:
export const sum=(num1,num2)=>num1+num2;
复制代码
动态导入:
let fun=async(num1,num2)=>{
let model=await import('./demo.js');
console.log(model.sum(num1,num2),"两个数的和")
}
fun(8,9)//17 "两个数的和"
//报错
//Access to script at 'file:///C:/Users/Administrator/Desktop/es11Demo/demo.js' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.
//demo.js:1 Failed to load resource: net::ERR_FAILED
//demo.html:13 Uncaught (in promise) TypeError: Failed to fetch dynamically imported module: file:///C:/Users/Administrator/Desktop/es11Demo/demo.js
//报错须要在http服务器环境下,才能够
复制代码
在当前项目的 根目录上建立http服务器 (电脑里面已经有node环境)
npm i http-server -g
安装依赖
而后在目录 里面 执行 http-server
JavaScript 在不一样的环境获取全局对象有不一样的方式,NodeJS 中经过 global
, Web 中经过 window
, self
等,有些甚至经过 this
获取,但经过 this
是及其危险的,this
在 JavaScript 中异常复杂,它严重依赖当前的执行上下文,这些无疑增长了获取全局对象的复杂性。
全局变量 window:是一个经典的获取全局对象的方法。可是它在 Node.js 和 Web Workers 中并不能使用
全局变量 self:一般只在 Web Workers 和浏览器中生效。可是它不支持 Node.js。
全局变量 global:只在 Node.js 中生效
咱们写的一个js文件,可能在浏览器上运行,也可能在node环境下运行,也可能在 Web Workers 环境中运行,
这时候的这个全局变量就不统一咱们可使用如下的方法去作一个判断,过去获取全局对象,可经过一个全局函数:
var getGlobal = function () {
if (typeof self !== 'undefined') { return self; }
if (typeofwindow !== 'undefined') { returnwindow; }
if (typeof global !== 'undefined') { return global; }
thrownewError('unable to locate global object');
};
var globals = getGlobal();
复制代码
而到咱们的ES11中为咱们提供了 globalThis
,
而 globalThis
目的就是提供一种标准化方式访问全局对象,有了 globalThis
后,你能够在任意上下文,任意时刻都能获取到全局对象。
globalThis 提供了一个标准的方式来获取不一样环境下的全局 this 对象(也就是全局对象自身),因此不用担忧运行环境。
// worker.js
console.log(globalThis === self) //true
// node.js
console.log(globalThis === global) //true
// 浏览器
console.log(globalThis === window) //true
复制代码
都知道 Promise.all
具备并发执行异步任务的能力。但它的最大问题就是若是其中某个任务出现异常(reject
),全部任务都会挂掉,Promise
直接进入 reject
状态。
想象这个场景:你的页面有三个区域,分别对应三个独立的接口数据,使用 Promise.all
来并发三个接口,若是其中任意一个接口服务异常,状态是 reject,这会致使页面中该三个区域数据全都没法渲染出来,由于任何 reject
都会进入 catch 回调, 很明显,这是没法接受的,以下:
let a= new Promise((resolve,reject)=>{
//异步操做...
resolve({ code: 200,msg:"请求成功"})
})
let b= new Promise((resolve,reject)=>{
//异步操做...
resolve({ code: 200,msg:"请求成功"})
})
let c= new Promise((resolve,reject)=>{
//异步操做...
reject({ code: 500,msg:"服务器出现异常"})
})
//使用Promise.all 进行并发执行异步任务
Promise.all([a,b,c])
.then((res) => {
// 只有 上面全部的请求都是 resolve (成功) 的时候才会进入此回调中
console.log(res,"res")
})
.catch((error) => {
// 上面的请求中,只要有一个是reject (失败) 就会进入此回调
console.log(error,"error")
// error: {code: 500, msg: "服务异常"}
})
复制代码
当咱们处理多个promise
时,尤为是当它们相互依赖时,记录每一个事件在调试中发生的错误可能颇有用。使用Promise.allSettled
,它会建立一个新的promise
,在全部promise
完成后返回一个包含每一个promise
结果的数组。
let a= new Promise((resolve,reject)=>{
//异步操做...
resolve({ code: 200,msg:"请求成功"})
})
let b= new Promise((resolve,reject)=>{
//异步操做...
resolve({ code: 200,msg:"请求成功"})
})
let c= new Promise((resolve,reject)=>{
//异步操做...
reject({ code: 500,msg:"服务器出现异常"})
})
//使用进行并发请求
Promise.allSettled([a,b,c]).then((data=>{
console.log(data,"data")
}))
// 返回的数据中 ,status: "fulfilled" 表示请求成功,status: "rejected" 表示请求失败
复制代码
Promise.allSettled
跟``Promise.all相似 都是进行并发请求,可是,咱们在上面的两个例子中,显然是已经看到了他们的一些区别,在使用
Promise.all进行并发请求的时候,只要有一个请求出现问题(异常),全部的请求正常的也都不能拿到数据,可是在咱们的业务的开发中,咱们须要保障咱们业务的最大的可访问性,就是在咱们执行并发任务中,无论我这个并发任务中的一任何个任务是正常仍是异常,咱们都须要拿到返回的对应的状态,在ES11中
Promise.allSettled就为咱们解决了这个问题,它和
Promise.all相似,参数接受一个Promise的数组,返回一个新的Promise,也就是说当Promise所有处理完成后,咱们能够拿到每一个Promise的状态, 而不论是否处理成功。咱们能够在
then里面经过
filter来过滤出想要的业务逻辑结果,这样就解决了
Promise.all` 的缺陷。