7个令人欢畅的JavaScript新特色,还带给了什么样

时间:2020-04-15 12:04来源:亚洲城ca88唯一官方网站
时间: 2019-12-24阅读: 60标签: nginx前言 今天的 JavaScript已经无处不在了,以传统的方式使用 JavaScript,开发者可以在各种 Web浏览器中创建 Web 应用;通过Node.js,可以开发命令行工具与服务

时间: 2019-12-24阅读: 60标签: nginx前言

今天的 JavaScript 已经无处不在了,以传统的方式使用 JavaScript,开发者可以在各种 Web 浏览器中创建 Web 应用;通过 Node.js,可以开发命令行工具与服务器等应用;而在桌面领域,通过基于 JavaScript 与 HTML、CSS 等 Web 技术的 Electron 框架可以构建跨平台桌面应用;React Native 则可以用来开发跨平台移动应用;此外,JavaScript 甚至可以在 IoT 设备上运行。

时间: 2019-11-04阅读: 72标签: 功能

一个ECMAScript标准的制作过程,包含了Stage 0到Stage 4 五个阶段,每个阶段提交至下一阶段都需要TC39审批通过。本文介绍这些新特性处于Stage 3 或者Stage 4 阶段,这意味着应该很快在浏览器和其他引擎中支持这些特性。

Ecma TC39 管理着 ECMAScript 生态的发展,它是当前 JavaScript 语言背后的标准,谷歌 V8 团队一直积极参与 JavaScript 相关标准化工作。

自 2015 年发布 ES6 以来,JavaScript 一直在快速发展,每次迭代中都会出现大量新功能。 JavaScript 语言规范的新版本每年更新一次,新语言功能建议的定稿比以往更快。这意味着新功能将以前所未有的速度被整合到现代浏览器和其他 JavaScript 运行时引擎(如 Node.js)中。

一、类的私有变量

V8 是谷歌开源的 JavaScript 引擎(同时也是 WebAssembly 引擎),前面提到的 Chrom、Node.js 与 Electron 等平台都基于 V8。同时除了 Chrome,基于 Chromium 的一系列 Web 浏览器,如 Opera 与即将正式发布的 Microsoft Edge 在底层也基于 V8。

在 2019年,“Stage 3”阶段有许多新功能,这意味着它即将完成,并且已经在浏览器和 Node 中获得对这些功能的支持。如果我们想将它们用于生产环境,则可以使用 Babel 之类的东西将其转换为旧版 JavaScript,以便在需要时用于旧版浏览器(如 Internet Explorer)。

最新提案之一是在类中添加私有变量的方法。我们将使用 # 符号表示类的私有变量。这样就不需要使用闭包来隐藏不想暴露给外界的私有变量。

在前几天的 Google I/O 2019 上,V8 团队的 Mathias Bynens 与 Sathya Gunasekaran 分享了 JavaScript 的最新研发进展。

在本文中,我们研究了类中的私有字段,可选链,无效合并运算符和BigInts。

classCounter{#x=0;​#increment(){this.#x  ;}​onClick(){this.#increment();}}​constc=newCounter();c.onClick();//正常c.#increment();//报错

图片 1

类的私有字段

通过 # 修饰的成员变量或成员函数就成为了私有变量,如果试图在 Class 外部访问,则会抛出异常。现在,此特性可在最新版本的 Chrome 和 Node.js中使用。

V8 团队表示,他们的使命是要领导现代 JavaScript 与 WebAssembly 高性能,值得关注的是,分享者用了“real-world”描述性能,并介绍所谓“real-world performance”是与那些单纯为了 benchmark 数据的性能相对的,谷歌强调想要达到的是实际上在现实生活中能够做到高性能的效果,而不是那么“出世”。

最新提案之一是在类中添加私有变量的方法。我们将使用#符号表示类的私有变量。这样就不需要使用闭包来隐藏不想暴露给外界的私有变量。例如我们可以编写一个简单的类来增加和减少数字,请看以下代码:

二、可选链操作符

他们举了几个例子。自 Chrome 61 以来,V8 团队将原始 JavaScript 解析速度提高了一倍,这些数据是在真实网站上测试得到的。同时他们已经成功从主线程中移除了 40% 的解析和编译工作,网页启动变得更加顺滑。

class Counter { #x = 0; increment() { this.#x  ; } decrement() { this.#x--; } getNum(){ return this.#x; }}const c = new Counter();c.increment(); c.increment(); c.decrement(); console.log(c.getNum());

你可能碰到过这样的情形:当需要访问嵌套在对象内部好几层的属性时,会得到臭名昭著的错误Cannot read property 'stop' of undefined,然后你就要修改你的代码来处理属性链中每一个可能的undefined对象,比如:

图片 2

代码中console.log输出的结果是 1。#x是一个私有变量,无法在类外部访问。所以如果我们这样写:

letnestedProp=objobj.firstobj.first.second;

除了 Chrome,速度提升在 Node.js 中也有很明显的体现,Node.js 12 相比 Node.js 7,async 速度提升了 10 倍,Promise.all 速度提升了 12 倍。

console.log(c.#x);

在访问obj.first.second之前,obj和obj.first 的值要被确认非null(且不是undefined)。目的是为了防止错误发生,如果简单直接的访问obj.first.second而不对obj和obj.first 进行校验就有可能产生错误。

图片 3

将会得到提示Uncaught SyntaxError: Private field '#x'。

有了可选链式调用 ,你只要这样写就可以做同样的事情:

解析速度与运行时性能提高之外,内存占用也减少了,Chrome 70 到 Chrome 76,Android 上运行实际 Web 应用的内存消耗减少了 20%

私有变量是 JavaScript 类非常需要的功能。现在,最新版本的 Chrome 和 Node.js v12 中已提供了此功能。

letnestedProp=obj?.first?.second;

图片 4

可选链运算符

如果obj或obj.first是null/undefined,表达式将会短路计算直接返回undefined。

接下来演讲者分享了 JavaScript 的一些新特性,涵盖内容很多,下边简单介绍几个比较有意思的特性:

当前,如果要访问对象的深层嵌套属性,则必须通过很长的布尔表达式去检查每个嵌套级别中的属性。必须检查每个级别中定义的每个属性,直到所需的深度嵌套的属性为止,如下代码所示:

三、空位合并操作符

使用方言口语化显示时间短语 API

const obj = { prop1: { prop2: { prop3: { prop4: { prop5: 5 } } } }}obj.prop1  obj.prop1.prop2  obj.prop1.prop2  obj.prop1.prop2.prop3  obj.prop1.prop2.prop3.prop4  console.log(obj.prop1.prop2.prop3.prop4.prop5);

我们在开发过程中,经常会遇到这样场景:变量如果是空值,则就使用默认值,我们是这样实现的:

这是众多新 Intl.* API 中的一种,也是观众讨论比较多的一个特性,Intl.* 是指国际化特性。

幸运的是,上面的代码在我们想要访问的每个级别中都定义了每个属性。但是,如果在任何级别的对象中都有undefined或null的嵌套对象,如果不进行检查,那么的程序将会崩溃。这意味着我们必须检查每个级别,以确保当它遇到undefined或null对象时不会崩溃。

letc=a?a:b//方式1letc=a||b//方式2

我们日常生活中提到时间的时候会说“上周”、“上个月”与“42 秒前”等口语,使用新的 Intl.RelativeTimeFormat() 函数,程序可以使用特定语言返回这些短语,而不是方方正正的“one week ago”、“one month ago”和“42 seconds ago”。

使用可选链运算符,只需要使用?.来访问嵌套对象。而且如果碰到的是undefined或null属性,那么它只会返回undefined。通过可选链,可以把上面的代码改为:

这两种方式有个明显的弊端,它都会覆盖所有的假值,如(0, '', false),这些值可能是在某些情况下有效的输入。

演讲者使用英语与泰米尔语演示了该功能,效果如下:

const obj = { prop1: { prop2: { prop3: { prop4: { prop5: 5 } } } }}console.log(obj?.prop1?.prop2?.prop3?.prop4?.prop5);

为了解决这个问题,有人提议创建一个“nullish”合并运算符,用 ?? 表示。有了它,我们仅在第一项为 null 或 undefined 时设置默认值。

图片 5

当我们的程序执行到undefined或null属性时,不会崩溃,而只是返回undefined。不幸的是,这尚未在任何浏览器中实现,所以最新版本的 Babel 来使用此功能。

letc=a??b;//等价于letc=a!==undefineda!==null?a:b;

图片 6

空位合并运算符

例如有以下代码:

目前该功能支持秒、分钟、小时、天、周、月与季的短语表示,并且支持多种语言(不清楚有没有中文支持),开发者不再需要维护一个专门的相对时间短语列表。

来自undefined或null值的另一个问题是,如果我们想要的变量为undefined或null则必须给变量设置默认值。例如:

constx=null;consty=x??500;console.log(y);//500constn=0constm=n??9000;console.log(m)//0

globalThis

consty = x ||500;

四、BigInt

想要编写适用于不同平台的 JavaScript,不管是 Node.js 还是 Web 浏览器,都需要有相应的代码来适配全局“this”,比如 Web 浏览器,需要使用“window”来判断,但在“window”不可用的情况下,还需要用“self”检查,在 Node 中可以用“global”判断,但如果是独立的 JavaScript shell 环境,那情况又有变化。

当使用||运算符将x设置为y时,如果x被定义为undefined,我们必须设置一个默认值。运算符||的问题在于,所有类似于 0,false或空字符串之类的值都将被我们不想要的默认值覆盖。

JS在Math上一直很糟糕的原因之一是,无法精确表示大于的数字2 ^ 53,这使得处理相当大的数字变得非常困难。

图片 7

为了解决这个问题,有人提议创建一个“nullish”合并运算符,用??表示。有了它,我们仅在第一项为null或undefined时设置默认值。使用无效的合并运算符,以上表达式将变为:

1234567890123456789*123;//-151851850485185200000//计算结果丢失精度

环境因素很复杂,各种平台环境需要进行繁杂的适配过程,这对于开发者来说会很痛苦,所以 V8 团队新增了一个“globalThis”特性,它可以在不依赖环境的情况下,轻松访问全局“this”。

consty = x ??500;

幸运的是,BigInt(大整数)就是来解决这个问题。你可以在BigInt上使用与普通数字相同的运算符,例如 , -, /, *, %等等。

目前 Chrome、FireFox、Safari 与 Node.js 都已经支持该特性,同时对于 polyfill 与其它需要全局访问“this”的库也适用,从这一点来说该特性是一个比较大的改进。

例如有以下代码:

创建 BigInt 类型的值也非常简单,只需要在数字后面加上 n 即可。例如,123 变为 123n。也可以使用全局方法 BigInt(value) 转化,入参 value 为数字或数字字符串。

WeakRef

const x = null;const y = x ?? 500;console.log(y); // 500const n = 0const m = n ?? 9000;console.log(m) // 0
constaNumber=111;constaBigInt=BigInt(aNumber);aBigInt===111n//truetypeofaBigInt==='bigint'//truetypeof111//"number"typeof111n//"bigint"

通常 JavaScript 中对象引用意味着只要对对象进行了引用,那么它就不会被 GC,而弱引用中,如果其它对象都不再引用该对象,那么 GC 机制会自动回收该对象所占用的内存,不考虑该对象是否还在该引用的结构中。

y将被分配的值为 500,因为x的值为null。但是,由于n不为null或unfined,因此m被赋予值为0。如果我们使用||而不是??,那么由于 0 为假,因此将为m赋值 9000。

只要在数字末尾加上 n,就可以正确计算大数了:

目前 JavaScript 中有 WeakMap 与 WeakSet 两个弱引用方法,只要将对象添加到 WeakMap 或 WeakSet 中,GC 在触发条件时就可以将其占用内存回收。

不幸的是,此功能尚未在任何浏览器或 Node.js 中实现,我们必须使用最新版本的 Babel 才能使用此功能。

1234567890123456789n*123n;//-151851850485185185047n

WeakRef 是一种更加高级的 API,它提供了一个进入对象生命周期的窗口,可以解决 WeakMap 仅支持 object 类型作为 Key 的场景。

BigInt

不过有一个问题,在大多数操作中,不能将 BigInt与Number混合使用。比较Number和 BigInt是可以的,但是不能把它们相加。

演讲者以缓存图像为例,map 会锁住图像的 Key 与 Value,这样图像名和图像数据就不会被 GC,因为它一直被引用着。另一方面,弱引用 WeakMap 在这里并不会起作用,因为图像名是一个字符串类型,而 WeakMap 规定其 Key 只能为 object 类型。

我们可以用 BigInt 对象表示大于的整数。可以通过常规操作(例如算术运算符)进行加、减、乘、除、余数和幂等运算。它可以由数字和十六进制或二进制字符串构造。此外它还支持 AND、OR、NOT 和 XOR 之类的按位运算。唯一无效的位运算是零填充右移运算符()。

1n2//true​1n 2//UncaughtTypeError:CannotmixBigIntandothertypes,useexplicitconversions

WeakRef 通过直接缓存图像对象的方法来解决这个问题,图像名作为 Key,WeakRef 弱引用作为 Value 存储在缓存中。但这会带来另一个问题:因为图像名是 Key,那 map 仍然会一直保留着这些图像名字符串。理想的情况是这些字符串也要被 GC。

同样,一元运算符 也不支持 Numbers 和 BitInts 之间的加法运输。仅当所有操作数均为BigInts时才执行这些操作。在 JavaScript 中BigInt与普通数字不同。它与普通数字的区别在于,数字的末尾带有一个n。

现在,此特性可在最新版本的 Chrome 和 Node.js中使用。

图片 8

我们可以使用 BigInt 工厂函数定义 BigInt。它有一个参数,该参数可以是整数或代表十进制整数、十六进制字或二进制的字符串。 BigInt 不能与内置 Math 对象一起使用。另外在数字与 BigInt 之间进行转换时必须小心,因为在将 BigInt 转换为数字时,BigInt 的精度可能会丢失,反之亦然。

五、static 字段

WeakRef 的解决方案是引用一个新的 API “FinalizationGroup()”,注册一个回调函数,在 GC 触发时从缓存中删除前边提到的“残留的图像名字符串”。

要定义 BigInt,如果要传递的参数是整数,可以像下面的码一样:

它允许类拥有静态字段,类似于大多数OOP语言。静态字段可以用来代替枚举,也可以用于私有字段。

图片 9

const bigInt = BigInt(1);console.log(bigInt);
classColors{//publicstatic字段staticred='#ff0000';staticgreen='#00ff00';​//privatestatic字段static#secretColor='#f0f0f0';​}​font.color=Colors.red;font.color=Colors.#secretColor;//出错

除了这几点,新的 JavaScript 语言特性还包括:

当我们运行到console.log语句时,它将输出1n。如果想将字符串传递给工厂函数,我们可以这样写:

现在,此特性可在最新版本的 Chrome 和 Node.js中使用。

  • class fileds 可以直接在 class 中初始化变量而不用写在构造函数中
  • 私有 setter 与 getter
  • String.matchAll 可以进行正则多次匹配
  • 提高数字可读性,numeric seperators 可以在写数字的时候使用“_”作为分隔符
  • 新的大数字类型 BigInt
  • 新增一些 Intl.* API,也就是用于国际化的 API,比如 Intl.NumberFormat 本地化格式化数字显示,Intl.RelativeTimeFormat() 与 Intl.DateTimeFormat() 本地化显示时间
  • 顶级 await,无需写 async
  • 新的 Promise 函数 Promise.allSettled() 与 Promise.any()
const bigInt = BigInt('2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222');console.log(bigInt);

六、Top-level await

具体内容可以查看演讲视频:

也可以通过使用以0x开头的字符串将十六进制数字字符串传递给工厂函数:

ES2017(ES8)中的 async/await 特性仅仅允许在 async 函数内使用 await 关键字,新的提案旨在允许 await 关键字在顶层内容中的使用,例如可以简化动态模块加载的过程:

const bigHex = BigInt("0x1fffffffffffff111111111");console.log(bigHex);
conststrings=awaitimport(`/i18n/${navigator.language}`);

(文/开源中国)    

当我们在bigHex上运行console.log时,上面的代码将输出为618970019642690073311383825n。

这个特性在浏览器控制台中调试异步内容(如 fetch)非常有用,而无需将其包装到异步函数中。

可以传入一个以0b开头的二进制字符串来获取 BigInt:

另一个使用场景是,可以在以异步方式初始化的 ES 模块的顶层使用它(比如建立数据库连接)。当导入这样的“异步模块”时,模块系统将等待它被解析,然后再执行依赖它的模块。这种处理异步初始化方式比当前返回一个初始化promise并等待它解决来得更容易。一个模块不知道它的依赖是否异步。

const bigBin = BigInt("0b111111111111111000000000011111111111111111111111");console.log(bigBin);
//db.mjsexportconstconnection=awaitcreateConnection();//server.mjsimport{connection}from'./db.mjs';server.start();

当我们在上面运行console.log时,上面的代码得到的结果是281466395164671n。如果要创建的 BigInt 超出数字类型可以接受的范围,则传递字符串会很方便。

在此示例中,在server.mjs中完成连接之前不会执行任何操作db.mjs。

还可以使用 BigInt 字面量去定义 BigInt 类型。方法在整数的末尾附加一个n字符。例如可以这样写:

现在,此特性可在最新版本的 Chrome中使用。

const bigInt = 22222222222222222222222222222222n;console.log(bigInt);

七、WeakRef

然后我们将22222222222222222222222222222222222n作为bigInt进行了输出。可以像使用数字一样对 BigInts 进行算术运算,例如 、-、/、*、%等。如果我们要使用 BigInts 进行这些操作,则所有操作数都必须都是 BigInts。但是如果我们得到了带小数点的结果,则小数点以后的部分将被截断。 BigInt 是一个大整数,不能存储小数。例如在下面的例子中:

一般来说,在 JavaScript 中,对象的引用是强保留的,这意味着只要持有对象的引用,它就不会被垃圾回收。

const expected = 8n / 2n;console.log(expected) // 4n const rounded = 9n / 2n;console.log(rounded) // 4n
constref={x:42,y:51};//只要我们访问ref对象(或者任何其他引用指向该对象),这个对象就不会被垃圾回收

我们得到expected和rounded的值都是4n。这是因为小数部分已从 BigInt 中删除。

目前在 Javascript 中,WeakMap 和 WeakSet 是弱引用对象的唯一方法:将对象作为键添加到 WeakMap 或 WeakSet 中,是不会阻止它被垃圾回收的。

比较运算符可以应用于 BigInts。操作数可以是 BigInt 或数字。例如可以将1n与1进行比较:

constwm=newWeakMap();{constref={};constmetaData='foo';wm.set(ref,metaData);wm.get(ref);//返回metaData}//在这个块范围内,我们已经没有对ref对象的引用。//因此,虽然它是wm中的键,我们仍然可以访问,但是它能够被垃圾回收。​constws=newWeakSet();ws.add(ref);ws.has(ref);//返回true
1n ===1

JavaScript 的 WeakMap 并不是真正意义上的弱引用:实际上,只要键仍然存活,它就强引用其内容。WeakMap 仅在键被垃圾回收之后,才弱引用它的内容。

上面的代码将评估为false,因为 BigInt 和数字不是同一类型。但是,当我们用双等号替换三等号时,如下面的代码所示:

WeakRef 是一个更高级的 API,它提供了真正的弱引用,Weakref 实例具有一个方法 deref,该方法返回被引用的原始对象,如果原始对象已被收集,则返回undefined对象。

1n ==1
constcache=newMap();constsetValue=(key,obj)={cache.set(key,newWeakRef(obj));};​constgetValue=(key)={constref=cache.get(key);if(ref){returnref.deref();}};​//thiswilllookforthevalueinthecache//andrecalculateifit'smissingconstfibonacciCached=(number)={constcached=getValue(number);if(cached)returncached;constsum=calculateFibonacci(number);setValue(number,sum);returnsum;};

上面的语句被评估为true,因为仅比较了该值。请注意,在两个示例中,我们都将 BigInt 操作数与数字操作数混合在一起。BigInts 和数字也可以与其他运算符一起进行比较,例如以下示例:

总而言之,JavaScript 中对象的引用是强引用,WeakMap 和 WeakSet 可以提供部分的弱引用功能,若想在 JavaScript 中实现真正的弱引用,可以通过配合使用 WeakRef 和终结器(Finalizer)来实现。

1n  9// true9n  1// true9  9n// false9n  9// false9n = 9// true

现在,此特性可在最新版本的 Chrome 和 Node.js中使用。

同样,它们可以混合在一起形成一个数组并进行排序。例如:

作者简介:

const mixedNums = [5n, 6, -120n, 12, 24, 0, 0n];mixedNums.sort();console.log(mixedNums)

浪里行舟:硕士研究生,专注于前端。个人公众号:「前端工匠」,致力于打造适合初中级工程师能够快速吸收的一系列优质文章!

现在,此功能可在最新版本的 Chrome 和 Node.js中使用。

总结

我们可以使用#号来表示私有类变量。这样就不必用闭包来隐藏我们不想暴露给外界的私有变量。为了解决对象中null和undefined值的问题,我们提供了可选链运算符来访问属性,而无需检查每个级别可能是null还是undefined。使用无效的合并运算符,我们只能为变量为null或undefined的情况设置默认值。使用 BigInt 对象,我们可以用 JavaScript 表示超出常规数字安全范围的大数字,并对其执行标准操作,只是小数部分将从结果中省略。

编辑:亚洲城ca88唯一官方网站 本文来源:7个令人欢畅的JavaScript新特色,还带给了什么样

关键词: 亚洲城ca88