让我们看看javascript中的一些新特性。本文将介绍它们的语法和相关链接,以帮助读者及时了解它们的进展。我们将通过编写一个小测试项目来演示如何快速使用这些新功能!

关于提案

提案分为五个阶段。有关详细信息,请参阅介绍文档https://tc39.github.io/process-document/。每项提案最初都以“斯特劳曼”或第0阶段休闲鹿提出,在这一阶段,它们要么没有提交给技术委员会,要么没有被否决,但尚未进入下一阶段。

作为个人建议,读者应避免在处于不稳定阶段的生产环境中使用阶段0建议。

以下提案均未进入第0阶段

创建测试项目

创建新目录并运行以下命令:

npm init -f

npm i ava@1.0.0-beta.3 @babel/preset-env@7.0.0-beta.42 @babel/preset-stage-0@7.0.0-beta.42 @babel/register@7.0.0-beta.42 @babel/polyfill@7.0.0-beta.42 @babel/plugin-transform-runtime@7.0.0-beta.42 @babel/runtime@7.0.0-beta.42 --save-dev`

然后将以下内容添加到package.json文件中:

{

"scripts": {

"test": "ava"

},

"ava": {

"require": [

"@babel/register",

"@babel/polyfill"

]

}

}

最后创建一个.babelrc文件:

{

"presets": [

[

"@babel/preset-env",

{

"targets": {

"node": "current"

}

}

],

"@babel/preset-stage-0"

],

"plugins": [

"@babel/plugin-transform-runtime"

]

}

现在可以开始写一些测试用例了!

1.可选运算符
在JavaScript中,我们一直在使用对象,但有时候对象里并不是我们期望的数据结构。假设下面是我们期望得到的数据,可能是通过调用API查询数据库得到的。

const data = {

user: {

address: {

street: "Pennsylvania Avenue"

}

}

}

如果该用户没有完成注册,可能得到下面的数据:

const data = {

user: {}

};

当尝试按下面的方式访问street时,会得到报错:

console.log(data.user.address.street);

// Uncaught TypeError: Cannot read property 'street' of undefined

为避免这种情况,需要按如下方式访问“street”属性:

const street = data && data.user && data.user.address && data.user.address.street;

console.log(street); // undefined`

在我看来,这种方法:

不美观

繁重

啰嗦

如果使用可选运算符,可以这样编码:

console.log(data.user?.address?.street);

// undefined

这样看起来更简单了,现在我们已经看到了这个功能的用处,现在来写一个测试!

import test from 'ava';

const valid = {

user: {

address: {

street: 'main street',

},

},

};

function getAddress(data) {

return data?.user?.address?.street;

}

test('Optional Chaining returns real values', (t) => {

const result = getAddress(valid);

t.is(result, 'main street');

});

我们看到了可选符号的正常使用,接下来是一些不规范数据的测试用例:

test('Optional chaining returns undefined for nullish properties.', (t) => {

t.is(getAddress(), undefined);

t.is(getAddress(null), undefined);

t.is(getAddress({}), undefined);

});

用于访问数组元素的用例:

const valid = {

user: {

address: {

street: 'main street',

neighbors: [

'john doe',

'jane doe',

],

},

},

};

function getNeighbor(data, number) {

return data?.user?.address?.neighbors?.[number];

}

test('Optional chaining works for array properties', (t) => {

t.is(getNeighbor(valid, 0), 'john doe');

});

test('Optional chaining returns undefined for invalid array properties', (t) => {

t.is(getNeighbor({}, 0), undefined);

});

有时我们不知道某个函数是否在对象中实现,一个常见的场景是,某些旧版浏览器可能没有某些功能,我们可以使用可选运算符接来检测函数是否已实现。看如下代码:

const data = {

user: {

address: {

street: 'main street',

neighbors: [

'john doe',

'jane doe',

],

},

getNeighbors() {

return data.user.address.neighbors;

}

},

};

function getNeighbors(data) {

return data?.user?.getNeighbors?.();

}

test('Optional chaining also works with functions', (t) => {

const neighbors = getNeighbors(data);

t.is(neighbors.length, 2);

t.is(neighbors[0], 'john doe');

});

test('Optional chaining returns undefined if a function does not exist', (t) => {

const neighbors = getNeighbors({});

t.is(neighbors, undefined);

});

如果调用链不完整,函数将不会执行,它背后的逻辑应该是这样的:

value == null ? value[some expression here]: undefined;

如果在可选链操作符之后是 undefined 或者 null则什么都不会执行,我们可以在以下测试中看到该规则的实际应用:

let neighborCount = 0;

function getNextNeighbor(neighbors) {

return neighbors?.[++neighborCount];

}

test('It short circuits expressions', (t) => {

const neighbors = getNeighbors(data);

t.is(getNextNeighbor(neighbors), 'jane doe');

t.is(getNextNeighbor(undefined), undefined);

t.is(neighborCount, 1);

});

有了可选运运算符,我们的代码中可以减少if语句、lodash等库以及&&进行链式调用的使用。

2.空值合并
以下是我们在JavaScript中看到的一些常见操作:

检查 null 或 undefined

给变量设置默认值

确保0,false和''不设置默认值

像这样:

value != null ? value : 'default value';

或者这样:

value || 'default value'

问题是,对于第二个实现,在值为0、false和''时都被视为false,所以我们必须明确检查null和undefined。

value != null

和上面相同:

value !== null && value !== undefined

这就是新提案的用武之地,现在我们可以这样做:

value ?? 'default value';

这可以保护我们不会为0、false和''设置默认值,在不使用三元运算符和!= null检查的情况下捕获null和undefined。

接下来编写一个简单的测试来验证它是如何工作的:

import test from 'ava';

test('Nullish coalescing defaults null', (t) => {

t.is(null ?? 'default', 'default');

});

test('Nullish coalescing defaults undefined', (t) => {

t.is(undefined ?? 'default', 'default');

});

test('Nullish coalescing defaults void 0', (t) => {

t.is(void 0 ?? 'default', 'default');

});

test('Nullish coalescing does not default 0', (t) => {

t.is(0 ?? 'default', 0);

});

test('Nullish coalescing does not default empty strings', (t) => {

t.is('' ?? 'default', '');

});

test('Nullish coalescing does not default false', (t) => {

t.is(false ?? 'default', false);

});

在测试中看到,??为null,undefined和void 0设置了默认值,没有为0,''和false设置默认值。

3.管道运算符
在函数式编程中,我们有一个概念叫compose,它多个函数调用合并在一起,调用时从右到左执行每个函数,函数接收前一个函数的输出作为其输入,以下是我们在纯JavaScript中讨论的一个示例:

function doubleSay (str) {

return str + ", " + str;

}

function capitalize (str) {

return str[0].toUpperCase() + str.substring(1);

}

function exclaim (str) {

return str + '!';

}

let result = exclaim(capitalize(doubleSay("hello")));

result //=> "Hello, hello!"

这种合并使用函数的方式很常见常见,以至于在于大多数功能库中,如lodash和ramda都有实现。

使用新的管道运算符,可以不使用第三方库并按如下所示编写上述内容:

let result = "hello"

|> doubleSay

|> capitalize

|> exclaim;

result //=> "Hello, hello!"`

这个提案目的是使链式调用函数更具可读性,在未来结合函数部分应用也可以很好的工作,类似下面这种使用方式:

let result = 1

|> (_ => Math.max(0, _));

result //=> 1

let result = -5

|> (_ => Math.max(0, _));

result //=> 0

编写如下测试用例:

import test from 'ava';

function doubleSay (str) {

return str + ", " + str;

}

function capitalize (str) {

return str[0].toUpperCase() + str.substring(1);

}

function exclaim (str) {

return str + '!';

}

test('Simple pipeline usage', (t) => {

let result = "hello"

|> doubleSay

|> capitalize

|> exclaim;

t.is(result, 'Hello, hello!');

});

test('Partial application pipeline', (t) => {

let result = -5

|> (_ => Math.max(0, _));

t.is(result, 0);

});

test('Async pipeline', async (t) => {

const asyncAdd = (number) => Promise.resolve(number + 5);

const subtractOne = (num1) => num1 - 1;

const result = 10

|> asyncAdd

|> (async (num) => subtractOne(await num));

t.is(await result, 14);

});

需要注意,一旦将async函数添加到管道,必须await该返回值,因为此时返回值是promise。有一提案开始支持|> await asyncFunction,但尚未实现。

最后,既然你已经看到了这些提案的实际应用,我希望你能够尝试一下这些提案!

javascript新特性的更多相关文章

  1. ES6:JavaScript 新特性

    我相信,在ECMAScript.next到来的时候,我们现在每天都在写的JavaScript代码将会发生巨大的变化.接下来的一年将会是令JavaScript开发者们兴奋的一年,越来越多的特性提案将被最 ...

  2. 7 个令人兴奋的 JavaScript 新特性

    前言 一个ECMAScript标准的制作过程,包含了Stage 0到Stage 4五个阶段,每个阶段提交至下一阶段都需要TC39审批通过.本文介绍这些新特性处于Stage 3或者Stage 4阶段,这 ...

  3. 七种武器:JavaScript 新特性闪亮登场

    JavaScript(或ECMA Script) 是一门不断发展的语言,有许多关于如何前进的建议和想法.TC39(技术委员会39)是负责定义JS标准和特性的委员会,今年他们非常活跃.以下是目前处于&q ...

  4. 6个小而美的es6新特性

    译者:动静若参商 译文:http://www.zcfy.cc/article/1795 原文:https://davidwalsh.name/es6-features JavaScript社区中的每个 ...

  5. ArcGIS API for JavaScript 4.2学习笔记[0] AJS4.2概述、新特性、未来产品线计划与AJS笔记目录

    放着好好的成熟的AJS 3.19不学,为什么要去碰乳臭未干的AJS 4.2? 4.2全线基础学习请点击[直达] 4.3及更高版本的补充学习请关注我的博客. ArcGIS API for JavaScr ...

  6. ECMAScript和JavaScript的区别,ECMAScript发展更新历史,ECMAScript5和ECMAScript6的新特性及浏览器支持情况,ECMAScript 5/ECMAScript 2015正式发布

    ECMAScript和JavaScript的区别 ECMA是European Computer Manufacturers Association的缩写,即欧洲计算机制造商协会.欧洲计算机制造商协会是 ...

  7. Atitit.js模块化 atiImport 的新特性javascript import

    Atitit.js模块化 atiImport 的新特性javascript import 1. 常见的js import规范amd ,cmd ,umd1 1.1. Require更多流行3 2. at ...

  8. 细解JavaScript ES7 ES8 ES9 新特性

    题记:本文提供了一个在线PPT版本,方便您浏览 细解JAVASCRIPT ES7 ES8 ES9 新特性 在线PPT ver 本文的大部分内容译自作者Axel Rauschmayer博士的网站,想了解 ...

  9. ArcGIS API for JavaScript 4.4学习笔记[新] AJS4.4和AJS3.21新特性

    ESRI官网悄无声息突然更新4.4和3.21,公众号也没有什么消息.照例,给大家看看这次更新有什么新特性吧. 1. AJS 4.4 官方更新日志:点我,比较详细.我在这里抽一些主干作为说明. 1.1 ...

随机推荐

  1. 小数组的读写和带Buffer的读写哪个快

    定义小数组如果是8192个字节大小和Buffered比较的话 定义小数组会略胜一筹,因为读和写操作的是同一个数组 而Buffered操作的是两个数组

  2. 002-创建型-03-单例模式(Singleton)【7种】、spring单例及原理

    一.概述 保证一个类仅有一个实例,并提供一个全局访问点 私有构造器.线程安全.延迟加载.序列化和反序列化安全.反射攻击 1.1.适用场景 1.在多个线程之间,比如servlet环境,共享同一个资源或者 ...

  3. 用python查看文件是否存在的三种方式

    目录 1.使用os模块 判断文件是否可做读写操作 2.使用Try语句 3. 使用pathlib模块 正文 通常在读写文件之前,需要判断文件或目录是否存在,不然某些处理方法可能会使程序出错.所以最好在做 ...

  4. jQuery补充之jQuery扩展/form表单提交/滚动菜单

    jQuery扩展 为了避免重复造轮子,能高效使用别人的代码,所以有了扩展. jQuery扩展有两种方式: 自执行函数方式 定义函数,并执行函数. 自执行函数: (function(jq){ jq.ex ...

  5. linux常用的命令和工具

    screen     管理会话工具 与之相似的工具还有tmux # screen // 进入一个回话 .还可以给会话取名 screen -S modify_screen #vim screen.txt ...

  6. orcale11g安装

    一.centos7.5安装orcale 安装环境 内存最小1G,推荐2G或者更高 内存为1-2g,swap是内存的1.5倍左右 内存大于2G, swap和内存相等 硬盘最小为30G oracle版本 ...

  7. java 工程编码格式由GBK转化成utf-8 (转载)

    import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import ja ...

  8. Linux 安装环境初始化检查 安装Nginx

    一 .阿里云 centos 6.8 32 位裸环境 实现:Linux Nginx mysql php redis 查看当前安装的服务 [root@iZgahlk1l73998Z etc]# servi ...

  9. Red Hat Enterprise 6.5 在虚拟机上将系统语言修改为中文

    Red Hat Enterprise 6.5 在虚拟机上将系统语言修改为中文 说明:本文是个人在使用RedHat时候为方便而设置的,作为学习札记记录. 在虚拟机安装RedHat时候会跳过语言的安装选项 ...

  10. Go之接口interface(1)

    1. 什么是interface在此之前,我们遇到的都是具体的类型,比如数字类型.切片类型等等.对于这些具体的类型,我们总是能知道它是什么.可以利用它来做什么,比如对于一个数字类型,我们知道可以对其进行 ...