ES11来了,不进来看看嘛

Symbol卢
• 阅读 1537

前言

ES2020 (ES11)是 ECMAScript 对应 2020 年的版本。这个版本不像 ES6 (ES2015)那样包含大量新特性。但也添加了许多有趣且有用的特性。本文以简单的代码示例来介绍 ES2020新特性。这样,你可以很快理解这些新功能,而不需要多么复杂的解释,好了,废话不多说我们进入正文🔛

私有变量

类的主要作用之一是将我们的代码包含在可重用的模块中。所以会在许多不同地方使用到同一个类,但是又的类里面的一些属性,为了安全或者是其他的目的,不想让其他的类能够去访问他,修改他,只能他自己用,对于一些学过c#,java等语言的同学来说是比较好理解的,就是 Private一个访问修饰符,那么在我们的js当中该怎么办了,

别担心,他们有的咱js也有,在ES11中也为我们提供了私有变量,通过在变量或函数前面添加一个哈希符号#,可以将它们设为私有属性,只在类内部可用。

这是我们普通的一个类

class Money{  
  constructor(money){  
    this.money=money;  
  }  
}  
let RMB=new Money(999);  
RMB.money=999999;//这还了得,怎么可以随便改钱的金额呢  
console.log(RMB.money);//可以通过对象的形式去访问  

由于安全,我们不能让其他的类来随便更改我们类里面的属性的值,我们可以使用 私有属性,是只能在类里面进行访问

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  

上面的代码报错了,哭唧唧ES11来了,不进来看看嘛,拿不到私有属性的值了,怎么办??

我需要使用我类里面的钱,怎么获取ES11来了,不进来看看嘛

我们可以在类里面写两个方法,取数据,写入数据,可以进行修改,但是你不能任意改,必须通过我的方法去改,我们可以看看下面的代码

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

好了,私有变量(属性),我们就说到这里了,下面我们来看看空值合并运算符吧!

空值合并运算符

在我们平常的工作中,在取一个对象里面的属性,如果这个属性没有值,我们会这样给他一个默认值

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")  

BigInt

关于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_INTEGERNumber.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 有两种方式:

  1. 在整数字面量后面加n
let bigIntNum1=9007199254740999n;  
console.log(typeof bigIntNum1)//bigint  
  1. 使用 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  

注意:

  1. BigInt 是一种新的数据原始(primitive)类型。注意标准数字与BigInt 数字不能混合使用。
`typeof 9007199254740993n; // -> 'bigint'  
`
  1. 尽可能避免通过调用函数 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

globalThis

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 缺陷

都知道 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.allSettled

当我们处理多个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" 表示请求失败  

ES11来了,不进来看看嘛

Promise.allSettled 的优势

Promise.allSettledPromise.all 类似 都是进行并发请求,但是,我们在上面的两个例子中,显然是已经看到了他们的一些区别,在使用 Promise.all进行并发请求的时候,只要有一个请求出现问题(异常),所有的请求正常的也都不能拿到数据,但是在我们的业务的开发中,我们需要保障我们业务的最大的可访问性,就是在我们执行并发任务中,不管我这个并发任务中的一任何个任务是正常还是异常,我们都需要拿到返回的对应的状态,在ES11中 Promise.allSettled 就为我们解决了这个问题,它和 Promise.all 类似,参数接受一个Promise的数组,返回一个新的Promise,也就是说当Promise全部处理完成后,我们可以拿到每个Promise的状态, 而不管是否处理成功。我们可以在 then里面通过 filter来过滤出想要的业务逻辑结果,这样就解决了Promise.all 的缺陷。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Symbol卢 Symbol卢
3年前
秒懂js作用域与作用域链
JavaScript中有一个被称为作用域(Scope)的特性。虽然对于许多新手开发者来说,作用域的概念并不是很容易理解,本文我会尽我所能用最简单的方式来解释作用域和作用域链,希望大家有所收获!好了下面开始我们的正文作用域常见的解释(什么是作用域)1.一段程序代码中所用到的名字并不总是有效,而限定它的可用性的范围就是这个名字的作用域;2.作用域规定了
凯特林 凯特林
3年前
ES 家族新特性,闪亮登场!
前言前端学习永无止境,学习吧骚年本文集合了ES6至ES11常用到的特性,包括还在规划的ES12,只列举大概使用,详细介绍的话内容量将十分巨大.。PS:使用新特性需要使用最新版的bable就行转义新特性ES6(2015)1\.类(class)class Man   constructor(name)     this.n
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
3个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
9个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这