让我们看看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. Python - Django - 作者表多对多关联书籍表

    models.py 代码: from django.db import models # Create your models here. # 出版社 class Publisher(models.M ...

  2. LeetCode_198. House Robber

    198. House Robber Easy You are a professional robber planning to rob houses along a street. Each hou ...

  3. Java点滴-List<Integer> list; 中尖括号的意思

    这是jdk1.5后版本才有的新特性,泛型,指定传入的类型.这样定义之后,这个list只能接收Integer的对象. 以前没有加这个,传入的都是Object类型的,取出来的时候要强制类型转换为自己想要的 ...

  4. iOS-AVPlayer使用

    1引入AVFoundation.framework框架 2引入头文件<AVFoundation/AVFoundation.h>,并拖入需要播放的视频文件 代码如下: 自定义播放的View, ...

  5. python2.7 urllib和urllib2

    urllib模块url编码和解码: 1.urllib.quote,urllib.quote_plus ,urllib.unquote ,urllib.unquote_plus urllib.quote ...

  6. eclipse 解决POM文件错误:org.apache.maven.archiver.MavenArchiver.getManifest(org.apache.maven.project.MavenProject, org.apache.maven.archiver.MavenArchiveConfiguration)

    解决方案: 更新eclipse中的maven插件 1.1 Help -> Install New Software -> Add 1.2 Location中输入 http://repo1. ...

  7. 【数据库开发】在Windows上和Linux上配置MySQL的过程

    [数据库开发]在Windows上和Linux上配置MySQL的过程 标签(空格分隔): [编程开发] 首先是在Windows上尝试用QT进行MySQL数据库开发,结果总出现driver不能load的错 ...

  8. 综合练习2 设置访问权限,Easy-IP访问外网,内外网访问

    实验拓扑图: 实验要求: 1.pc.路由.交换基本配置,vlan间路由互通. 2.vlan20.vlan30可以访问FTP,VLAN10不允许访问FTP. 3.AR1通过easy-ip方式实现私网地址 ...

  9. element-ui中的表格嵌套表格

    element-ui中有详细的各种表格及表格方法.也有表格展开出现二级的样式,但是却没有表格嵌套二级表格的方案,于是就自己写了一个,样式图如下: 展开后如下 这就是一个普通的二级表格嵌套,用的是el- ...

  10. FineReport做成之后如何在Tomcat上运行

    问题描述: 自己用FineReport做成的报表画面,要在Tomcat上运行启动 第一步:下载Tomcat 网址: http://tomcat.apache.org/download-80.cgi 下 ...