javascript新特性
让我们看看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新特性的更多相关文章
- ES6:JavaScript 新特性
我相信,在ECMAScript.next到来的时候,我们现在每天都在写的JavaScript代码将会发生巨大的变化.接下来的一年将会是令JavaScript开发者们兴奋的一年,越来越多的特性提案将被最 ...
- 7 个令人兴奋的 JavaScript 新特性
前言 一个ECMAScript标准的制作过程,包含了Stage 0到Stage 4五个阶段,每个阶段提交至下一阶段都需要TC39审批通过.本文介绍这些新特性处于Stage 3或者Stage 4阶段,这 ...
- 七种武器:JavaScript 新特性闪亮登场
JavaScript(或ECMA Script) 是一门不断发展的语言,有许多关于如何前进的建议和想法.TC39(技术委员会39)是负责定义JS标准和特性的委员会,今年他们非常活跃.以下是目前处于&q ...
- 6个小而美的es6新特性
译者:动静若参商 译文:http://www.zcfy.cc/article/1795 原文:https://davidwalsh.name/es6-features JavaScript社区中的每个 ...
- ArcGIS API for JavaScript 4.2学习笔记[0] AJS4.2概述、新特性、未来产品线计划与AJS笔记目录
放着好好的成熟的AJS 3.19不学,为什么要去碰乳臭未干的AJS 4.2? 4.2全线基础学习请点击[直达] 4.3及更高版本的补充学习请关注我的博客. ArcGIS API for JavaScr ...
- ECMAScript和JavaScript的区别,ECMAScript发展更新历史,ECMAScript5和ECMAScript6的新特性及浏览器支持情况,ECMAScript 5/ECMAScript 2015正式发布
ECMAScript和JavaScript的区别 ECMA是European Computer Manufacturers Association的缩写,即欧洲计算机制造商协会.欧洲计算机制造商协会是 ...
- Atitit.js模块化 atiImport 的新特性javascript import
Atitit.js模块化 atiImport 的新特性javascript import 1. 常见的js import规范amd ,cmd ,umd1 1.1. Require更多流行3 2. at ...
- 细解JavaScript ES7 ES8 ES9 新特性
题记:本文提供了一个在线PPT版本,方便您浏览 细解JAVASCRIPT ES7 ES8 ES9 新特性 在线PPT ver 本文的大部分内容译自作者Axel Rauschmayer博士的网站,想了解 ...
- ArcGIS API for JavaScript 4.4学习笔记[新] AJS4.4和AJS3.21新特性
ESRI官网悄无声息突然更新4.4和3.21,公众号也没有什么消息.照例,给大家看看这次更新有什么新特性吧. 1. AJS 4.4 官方更新日志:点我,比较详细.我在这里抽一些主干作为说明. 1.1 ...
随机推荐
- OpenNebula概述
OpenNebula概述 OpenNebula是专门为云计算打造的开源系统,用户可以使用Xen.KVM.VMware等虚拟化软件一起打造企业云.利用OpenNebula可以轻松构建私有云.混合云.公开 ...
- 机器学习 - 算法示例 - Xgboost
安装 能直接安装就再好不过 pip install xgboost 如果不能就下载之后本地安装 安装包下载地址 这里 想要啥包都有 数据集 pima-indians-diabetes.csv 文件 调 ...
- js实现文本框支持加减运算的方法
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/T ...
- Java多线程中thread.getname()和thread.currentThread().getName();的去别
首先要明白 this.XXX 的使用场景 使用Thread.currentThread().getName()和使用this.getName()和对象实例.getName(),都可以得到线程的名称,但 ...
- IfcRelDefinesByProperties IfcPropertySetDefinitionSelect IfcPropertySetDefinition IfcPropertySetDefinitionSet
private void updateObject(IfcObject ifcObject, PropertyNode root) { /* if(ifcObject.getClassName().t ...
- Greenwich.SR2版本的Spring Cloud Config+BUS实例
Spring Cloud Config统一的配置中心同注册中心Eureka一样,也分服务端和客户端.服务端用来保存配置信息,客户端用来读取.它的优势是基于Git仓库,支持多环境.多分支配置.动态刷新. ...
- 【c# 学习笔记】构造函数
构造函数 主要用于创建类的实例对象.当调用构造函数创建一个对象时,构造函数会为对象分配内存空间,并初始化类的成员.构造函数分为实例构造函数和静态构造函数两种. 1.实例构造函数 实例构造函数用于创建和 ...
- [Python[CV2]] -- 352: error -- 来自截取图片
今天想用CV2 截个ROI ( Region Of Interest ) 的时候, 是这样写的 结果, 发现是截取img 那句出了错 应该为: 先纵后横 这样就OK了 cv2.selectROI 用法 ...
- 移动架构-IOC架构设计
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度.其中最常见的方式叫做依赖注入(Dependency Inject ...
- git学习链接---收藏----
Github 创建新分支:https://blog.csdn.net/top_code/article/details/51931916Git易百教程:https://www.yiibai.com/g ...