最全 ECMAScript 攻略

5,117

很多人都在说,「嘿!这是最新的 ES6 语法」,「那又是 es7 的新特性」。那 ES 到底是什么呢? ES6/ES7/ES8/ES9 都有些什么东西呢?跟 Javascript 又有什么关系呢? 如果让你写一篇 ECMAScript 的文章你会如何列出目录呢?那么下面就让我从个方面带大家深入了解 ECMAScript 并建立一个详细的知识体系

什么是 ECMAScript

我们先从官方的的角度看看 ECMAScript 是什么?

ECMAScript 是由网景的布兰登·艾奇开发的一种脚本语言的标准化规范

规定了 JavaScript 语言的语法、类型、语句、关键字、保留字、操作符和对象。

这里我们主要注意标准化规范 这个词, 什么是标准化规范 呢?

下面我举一个例子来方便大家理解

20210531093601

想必大家偶尔会网购一些需要自己组装的小家具,其中必然带有一张类似的“家具组装说明书”。 它指示我们从第一步到最后一步如何把一个个小零件组装是一个完整的家具

因此这个“说明书”  就是实现一个完整家具标准规范

上面是一张"家具组装说明书",家具买回来是一堆零件,不是一个完整的家具。需要我们根据说明书组装成一个真正的家具。

那么这张"说明书" 就是组装成一个真正的家具标准和规范

那么类比 JavaScript 也是一样的!

20210531093738

上图中就是实现 IsArray API 的 ECMAScript 规范,此规范具体描述了从第一步到最后一步实现 IsArray 方法的详细步骤,

有了这样的详细的规范后,再使用 JS 各种 API 进行实现。结果就有了我们现在使用的各种 JavaScript 核心 API

我们平常使用的各种现成的 JavaScript API 就相当于组装好的家具,ECMAScript 就是实现各种 JavaScript API 的标准和规范

相信经过这样的的类比后,大家都能很大致的明白 ECMAScript 是什么了吧?

ECMAScript 的发展历史

20210531093911

  • 1995 年 网景公司为了推广自己浏览器,需要开发一款脚本语言,这项重任就落到了 Brendan Eich 大神身上, 他仅仅花了 10 多天的时间 开发了一个叫 Mocha 的脚本语言,最后为搭上当时热烈炒作 Java 的顺风车,改名为 JavaScript。由此 JavaScript 诞生了

  • 1997 年, 网景公司将 JavaScript1.1 版本作为提案被提交给欧洲计算机制造商协会 ,也就是 Ecma 国际协会进行标准化。 第 39 技术委员会 ,也就是 TC39 承担了标准化了定义, 由此 ECMAScript 诞生了

  • 直到 2015 年,发布ECMAScript的第6个版本,断断续续一共发布 7 个版本(其中 4 被废弃)。

而且大家都知道 ,ES5ES6 发布的内容非常之多

又因为 之前的版本因为各种争论导致发行速度太慢, ES4 还一度被抛弃 为了解決这个问题,在 ES6 发布以后,TC39 规定每年都会发布新的版本。

因此我们通常把 ES5 及其之前的 版本统称做  ES5

ES6 及其 版本之后统称做  ES6+

当然, 为了明确区分各个版本的内容, 可以按照版本发布的时间进行描述, 比如 ES2015,ES2016

说了这么多,那我们为什么要学习和理解 ES 呢?

为什么要学习 ECMAScript

ECMAScript 是 JavaScript 的核心

在浏览器中中,JavaScript 主要包含三个部分

  • ECMAScript
  • BOM
  • DOM

JavaScript-web

下面是 Node 环境中的几大组成部分,可以发现 ECMAScript 当然是居于核心地位

JavaScript-node

ECMAScriptJavaScript 的核心 API 进行了规范,然后 JavaScript 对其进行了实现,比如:关键字保留字,变量数据类型函数操作符...

如果要更好的学习 JavaScript, 理解 ECMAScript 及其规范 是必不可少的一环

学习一门语言理解了最核心的东西,才能更好地掌握这门语言! 然后再开始真正的程序开发,这样我们的程序开发过程才会变得更加顺利。

更容易理解 API 的设计思路

网上有很多手写实现 JavaScript API 的高赞文章,比如这篇。我们要做应该是理解为什么会通过那样的方式手写实现 JavaScript API,而不是靠死记硬背。

那么理解的途径就是查阅 ECMAScript 的标准,这其实有点像是测试用例,这可以让我们思考一個 API 应该怎么设计,

像是下图中,如果要实现 isArray 就必須符合以下标准/规范:

isarray

  1. 传入的参数是否不是 Object,如果不是则返回 false
  2. 传入的参数是否是[object Array],如果是则 返回 true
  3. 判断是否是 Proxy
    1. Proxy 必须存在 hanlder
    2. proxy 必须返回原始参数
// ES5 版本的实现
Array.myIsArray = function (o) {
  return Object.prototype.toString.call(Object(o)) === "[object Array]";
};

// 方式二
const proxies = new WeakSet();

function createProxy(target, handler) {
  const proxy = new Proxy(target, handler);

  proxies.add(proxy);
  return proxy;
}

function isProxy(obj) {
  return proxies.has(obj);
}

var mydata = createProxy([], {
  get(target, phrase) {
    // 拦截读取属性操作
    if (phrase in target) {
      //如果词典中有该短语
      return target[phrase]; // 返回其翻译
    } else {
      // 否则返回未翻译的短语
      return phrase;
    }
  },
});

console.log(mydata.a);

Array.prototype.myisArray = function (arg) {
  if (typeof arg !== "object") {
    return false;
  }
  if (typeof arg === "object" && arg instanceof Array) {
    return true;
  }
  if (isProxy(arg)) {
    // 1. Proxy 必须存在hanlder
    // 2. proxy必须返回原始参数
    return Array.prototype.myisArray(arg.none);
  }
  return false;
};

console.log(Array.prototype.myisArray(mydata));

理解 ECMAScript 在各浏览器的兼容性

20210531094600

基于现在信息呈现的载体越来越丰富,用户可以通过各种终端来浏览信息,比如 PC 端览器,PC 端应用程序,移动端浏览器等,那么相应的对前端技术人员的要求也会越来高,因此前端人员需要更多的去了解各个浏览器的特性。

那么 ECMAScript 就是一个很好的说明书。

不同的浏览器厂商均以 ECMAScript 作为自己 JavaScript 实现的依据,但具体实现各有不同

有些只支持了 ES5,有些支持了 ES6,有些支持了 ES7 透过规范我们才可以知道哪些特性 API 可以直接使用,哪些特性没有在规范中(需要通过 babel 进行编译降级)

图中的网站我们就可以发现

所有浏览器都支持的版本是 ES5 , 并且 Chrome 是支持 ES 特性最多的浏览器

ECMAScript 规范是指定的 5 个阶段

20210531094928

在 ECMAScript 规范中进行更改的过程由 TC39 完成,称为 TC39 过程。 从零阶段开始,此过程分为五个阶段。

  1. Stage 0:Strawman - 对规范的补充或更改的初步构想
  2. Stage 1:Proposal- 提案(目的、解決方法) 问题并提出适当解决方案的正式建议
  3. Stage 2:Draft - 草案(提案提案规范编写初稿)
  4. Stage 3:Candidate -至少一个浏览器已经实现。几乎是最终稿,但还接受反馈并修改关键问题
  5. Stage 4:Finished - 审核完毕,至少两个浏览器已经实现,提案已准备好包含在最新的规范中-并随下一个版本一起发布

类似一个公司产品需求的完成

  1. Stage 0-产品提出需求
  2. Stage 1-组织大家进行需求评审,收集各方建议
  3. Stage 2-产品将收集的建议和需求进行排期
  4. Stage 3-实现 v1.0 需求发布到预生产环境并收集用户及公司内部反馈
  5. Stage 4-将反馈再进行排期实现 v2.0 并发布到正式环境

那 ECMAScript 发布成功后变成了一个什么东西呢?

20210531095152

ECMAScript 发布成功后会在公网上形成一份叫ECMA-262标准规范文档,如果我们想知道某个 JS API 如何实现,ECMA262 就是最原始的最官方的文档

谁可以制定 ECMAScript 规范/如何提交?

方式一: 直接联系 TC39 成员.

20210519205351

但是鉴于墙和国外大佬联系不方便的原因,此方式不推荐

方式二(推荐): 参加 JavaScript 中文兴趣组讨论

JavaScript 语言标准(ECMAScript)中文讨论 简称JSCIG

3301

3

JS 中文兴趣组是由贺师俊老师牵头组建、阿里巴巴等大厂,以及中国 ES 社区活跃的同学一起组成的社区

旨在代表国内的广大 JS 开发者,在语言使用效能方面向 TC39 技术委员会提出建议。

JS 中文兴趣组在 GitHub 上开放讨论各种 ES 的问题,非常欢迎有兴趣的同学可以参与讨论

下面到了大家最关心的环境了,ES 的 每个版本都有哪些特性呢?

ECMAScript 每个版本都有哪些特性?

Intl API

为什么要把Intl API 单独拿一节出来呢?

因此Intl API在工作中是非常实用的

我们前面分享的 ES 各个版本都在名为 ECMA262 的规范文件中

Intl API 的内容实在名为 ECMA402的规范文件中

20210531100018

Intl  对象是 ECMAScript 国际化 API 的一个命名空间,它提供了精确的字符串对比、数字格式化,和日期时间格式化。

CollatorNumberFormat  和  DateTimeFormat  对象的构造函数是  Intl  对象的属性。

Intl API 的标准单独起了一块(在 ECMA424 中) .而不在 ECMA262 中

Intl 对象是 ECMAScript 国际化 API 的一个命名空间,它提供了精确的字符串对比、数字格式化,和日期时间格式化。

Collator,NumberFormatDateTimeFormat对象的构造函数是Intl` 对象的属性。本页文档内容包括了这些属性,以及国际化使用的构造器和其他语言的方法等常见的功能。

场景: 通过 Intl API 对字符串,数字和日期进行国际化

日期格式化

// 例如我们希望出现的日期信息格式是:“xxxx年xx月xx日 xx:xx:xx”。
const res = new Intl.DateTimeFormat("zh", {
  year: "numeric",
  /* 
        '2-digit'表示一定使用2位数字表示,
        因此,如果数值不超过10,会自动在前面加0
  */
  month: "2-digit",
  day: "2-digit",
  hour: "2-digit",
  minute: "2-digit",
  second: "2-digit",
  // 设置为false表示我们采用24小时制
  hour12: false,
}).format(new Date());

// IE11浏览器下的效果 完全符合我们的预期, - 2021年05月29日 10:15:27
// 但是在Chrome浏览器和Firefox浏览器下,却不是中文的年月日而是斜杠-2021/05/29 10:15:27, 还需要进一步字符处理下
console.log(res);

数字格式化

连续数字千位分隔符分隔

new Intl.NumberFormat().format(12345.6789);
// 结果是:"12,345.679"

数字不足位数补 0

字符串补全 ES6 有现成的 API,padStart()和 padEnd(),不过 IE 不支持。

如果遇到需要数字补全,可以试试这里的 format()方法,IE11+都支持。

例如,希望小于 10 的数字前面都有 0,可以这么处理:

new Intl.NumberFormat(undefined, {
  minimumIntegerDigits: 2,
}).format(8);
// 结果是:"08"

金额中文自带

给一串数字,后面自带中文“元”。可以如下设置:

new Intl.NumberFormat("zh-Hans", {
  style: "currency",
  currency: "CNY",
  currencyDisplay: "name",
}).format(12345.6789);
// 结果是:"12,345.68 人民币"

数字变成中文数字显示

例如,我们要显示星期几,不需要再弄个数组进行一一映射了,试试下面的方法:

const res = `星期${new Intl.NumberFormat("zh-Hans-CN-u-nu-hanidec").format(
  new Date().getDay(),
)}`;
// 结果是:"星期五"

中文排序

Intl.Collator 对象

collator 这个单词意思是排序器。Intl.Collator 对象是排序器的构造函数,可以支持对语言敏感的字符串比较。

如果我们希望我们的中文按照首字母拼音排序,该怎么处理?

此时,可以使用中文简体的 BCF 47 语言标记字符串 zh 进行排序,代码如下:

var arrUsername = [
  "陈坤",
  "邓超",
  "杜淳",
  "冯绍峰",
  "韩庚",
  "胡歌",
  "黄晓明",
  "贾乃亮",
  "李晨",
  "李易峰",
  "鹿晗",
  "井柏然",
  "刘烨",
  "陆毅",
  "孙红雷",
];

arrUsername.sort(new Intl.Collator("zh").compare);
// 结果是:["陈坤", "邓超", "杜淳", "冯绍峰", "韩庚", "胡歌", "黄晓明", "贾乃亮", "井柏然", "李晨", "李易峰", "刘烨", "陆毅", "鹿晗", "孙红雷"]

参考文档

最后

㊗️贺我国首个 JS 语言提案在 ECMA 进入 Stage 3

文章浅陋,欢迎各位看官评论区留下的你的见解!

觉得有收获的同学欢迎点赞,关注一波!

20210531095857

往期文章