行将到来 Javascript 三个转变, 你会很喜欢它们的,由于确实是方便了许多!

《行将到来 Javascript 三个转变, 你会很喜欢它们的,由于确实是方便了许多!》

想浏览更多优良文章请猛戳GitHub博客,一年百来篇优良文章等着你!

让我们看看JavaScript中一些有效的行将涌现的特征。你将看到它们的语法、常常关注它们的愿望与更新。在此,我们将编写一个小测试案例来展现怎样从今天最先运用这些特征!

假如您已熟习Ecma TC39委员会怎样决议和处置惩罚JavaScript言语的变动,请跳过这一部份。

JavaScript是 ECMAScript 的言语范例的完成,ECMAScript 是在web浏览器的初期生长历程当中为范例范例化言语的完成而降生的。

ECMAScript范例有8个版本,7个宣布(第4个版本被摒弃了)。

JavaScript引擎在每次宣布后最先实行指定的特征晋级。这个图表申明并非每一个引擎都能完成了新出的每一个特征,而且一些引擎完成这些特征的时候要比其他引擎长。这好像不是最理想的,但我置信这总比没有范例要好。

草拟

每一个ECMAScript版本都要经由一个考核起稿的历程。假如一个草拟发起被认为是有效的和向后兼容的,它将被包括鄙人一版中。

这个地点 概述了提案的五个阶段。每一个提案都是从一个“strawman”或最初提出的 stage-0 最先的。在这一级,它们要么还没有提交给手艺委员会,要么还没有被谢绝,但仍未到达进入下一阶段的范例。

下面所示的草发起没有一项处于stage-0。

作为个人引荐,我发起读者在临盆运用顺序中防备运用stage-0发起,直到它们处于稳固的阶段。此发起的目标只是防备在草拟发起被摒弃或发作严重带来的贫苦。

好了,背景就烦琐到这里了,须要运用这些新出来的特征,还须要以下步骤:

始化项目、装置依靠(前提须要装置node.js,nmp)

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.46 
@babel/plugin-proposal-pipeline-operator
@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",
      {
        "decoratorsLegacy": true,
        "pipelineProposal": "minimal"
      }
    ]
  ],
  "plugins": [
    "@babel/plugin-transform-runtime",
      [
        "@babel/plugin-proposal-optional-chaining",
        {
          "loose": false
        }
      ],
      [
        "@babel/plugin-proposal-decorators",
        {
          "decoratorsBeforeExport": false
        }
      ],
      [
        "@babel/plugin-proposal-class-properties"
      ],
      [
        "@babel/plugin-proposal-pipeline-operator",
        {
          "proposal": "minimal"
        }
      ]
  ]
}

接下,我们写个粟子把行将出来 JavaSrcipt 特征用起来吧!

自推断链接(Optional Chaining)

Optional Chaining 能搜检一个对象上面是不是存在某属性,我们项目中,假如有一个用户对象有以下构造:

const data = {
  user: {
    name: '小智',
    address: {
      street: '小智测试地点',
    }, 
  },
};

但现实项目中,我们 user 内里数据是要求猎取,然后我们在赋值给 user,所以现实项目中我们平常会这么写:

const data = {
  user: {},
};

假定我们在顺序要读取 user中的 street, 我们会如许写 data.user.address.street,恩,这时候我们在控制台就会收到来自谷歌的赤色问候:

console.log(data.user.address.street); // Uncaught TypeError: Cannot read     property 'street' of undefined

为了防备失足,我们会如许写:

const street = data && data.user && data.user.address && data.user.address.street;
console.log(street); // undefined

我的感觉,这类写法:

1)貌寝
2)烦琐冗杂
3)狗屎

行将涌现的特征中,我们能够如许写:

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

如许是不是是越发简约轻易呢?既然我们看到了这个特征的有效性,我们就能够继承深入研究了!

写个粟子(test.js):

// test.js
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');
});

测试:

npm test

如今我们看到自推断链接保护了点标记的先前功用。接下测试一下,一连串的 .属性 操纵:

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

偶然我们不知道函数是不是在对象中完成,一个罕见的例子是在运用web浏览器时。一些较老的浏览器能够没有某些功用。荣幸的是,我们能够运用自推断链接来检测函数是不是完成了!

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

假如链不完整,表达式将不实行。在JavaScript引擎下,表达式粗略地转换成这个:

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

在“自推断链接” ?以后,假如值未定义或为空,则实行。我们能够鄙人面的测试中看到该划定规矩的作用:

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)和&&操纵标记的须要。

您能够会注意到,运用这个“自推断链接”具有最小的开支。你搜检的每一级”?“必需隐藏在某种前提逻辑中。假如运用过分,将致使机能下落。

下面是我们在JavaScript中看到的一些罕见操纵:

  1. 搜检null或许undefined的值
  2. 设置默许值
  3. 推断值是不是为 0,null, ”

你能够见过如许做的:

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

或许你能够见过这类不适当的做法:

value || 'default value'

问题是关于这两个完成,我们的三目运算符前提没有满足。在这个场景中,数字0、false和空字符串都被认为是假的。这就是为何我们必需搜检null和 undefined。

value != null

与之雷同的是:

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

这个就是 Nullish 兼并涌现缘由,我们能够如许做:

value ?? 'default value';

这就能够防备默许那些不可靠的值(null,undefined),替代三目运算和 !=null 的操纵;

写个测试粟子:

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,效果为undefined。它不会默许false值,如0、”和false.

管道操纵符

在函数式编程中,我们有一个术语“组合”,它是将多个函数挪用链接在一起的行动。每一个函数吸收前一个函数的输出作为输入。下面是我们用一般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!"

这类串接异常罕见,以至于组合函数涌如今大多数函数库中,比方lodashramda

运用新的管道操纵符,您能够跳过第三方库,像如许编写上面的代码:

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

好了,如今您已看到了这些新特征的现实运用,愿望不久的你能够闇练的尝试它!

你的点赞,是我延续分享好东西的动力,迎接点赞!

迎接到场前端大家庭,内里会常常分享一些手艺资本。

《行将到来 Javascript 三个转变, 你会很喜欢它们的,由于确实是方便了许多!》

    原文作者:前端小智
    原文地址: https://segmentfault.com/a/1190000017132261
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞