对Babel的研究

   

 Babel是一个工具链,主要用于将ECMAScript 2015+版本的代码转换为向后兼容的JavaScript语法,可以使之运行在当前和旧版本的浏览器或其他环境中。下面列出的是Babel能为你做的事情:

  • 语法转换
  • 通过Polyfill方式在目标环境中添加缺失的特性(通过@ babel / polyfill模块)
  • 原始码转换(codemods)

// Babel 输入: ES2015 箭头函数 [1, 2, 3].map((n) => n + 1); // Babel 输出: ES5 语法实现的同等功能 [1, 2, 3].map(function(n) { return n + 1; });

JSX与React

Babel能够转换JSX语法!查看反应预设了解更多信息。通过和babel-sublime一起使用还可以把语法高亮的功能提升到一个新的水平。

通过以下命令安装此预置

npm install --save-dev @babel/preset-react

将会@babel/preset-react添加到你的Babel配置文件中。

export default React.createClass({ getInitialState() { return { num: this.getRandomNumber() }; }, getRandomNumber() { return Math.ceil(Math.random() * 6); }, render() { return <div> Your dice roll: {this.state.num} </div>; } });

类型注释(Flow和TypeScript)

Babel可以删除类型注释!查看流预设TypeScript预设了解如何使用。严重牢记Babel不做类型检查,你仍然需要安装Flow或TypeScript来执行类型检查的工作。

通过以下命令安装

npm install --save-dev @babel/preset-flow

// @flow function square(n: number): number { return n * n; }

或通过以下命令安装打字稿预设

npm install --save-dev @babel/preset-typescript

function Greeter(greeting: string) { this.greeting = greeting; }

插件化

Babel内置在插件之上。使用现有的或者自己编写的插件可以组成一个转换管道。通过使用或创建一个预设即可轻松使用一个插件。了解更多→

利用astexplorer.net可以立即创建一个插件,或者使用generator-babel-plugin生成一个插件模板。

// 一个插件就是一个函数 export default function ({types: t}) { return { visitor: { Identifier(path) { let name = path.node.name; // reverse the name: JavaScript -> tpircSavaJ path.node.name = name.split('').reverse().join(''); } } }; }

可调试

由于Babel支持源地图,因此您可以轻松调试编译后的代码。

符合规范

Babel尽最大可能遵守ECMAScript标准。不过,Babel还提供了特定的选项来对标准和性能做权衡。

代码精细

Babel尽量使用最少的代码和不依赖太大量的运行环境。

有些情况是很难达成的这一愿望的,因此Babel提供了“ loose”参数,可以在特定的转换情况下在符合规范,文件大小和速度之间做折中。

本指南将向您展示如何将使用ES2015 +语法的JavaScript应用程序代码编译为可在当前浏览器中使用的代码。这将涉及转换新语法和填充缺少的功能。

整个设置过程包括:

  1. 运行以下命令以安装软件包:

         npm install --save-dev @babel/core @babel/cli @babel/preset-env

         npm install --save @babel/polyfill

         2.babel.config.js使用以下内容在项目的根目录中创建一个名为config的配置文件

         const presets = [ [ "@babel/env", { targets: { edge: "17", firefox: "60", chrome: "67", safari: "11.1", }, useBuiltIns: "usage", }, ], ]; module.exports = { presets };

        3.然后运行此命令,将src目录中的所有代码编译lib

         ./node_modules/.bin/babel src --out-dir lib

CLI的基本用法

您需要的所有Babel模块都作为单独的npm软件包发布,其范围为@babel(自版本7起)。这种模块化设计允许使用各种工具,每种工具都是针对特定用例设计的。在这里,我们将看看@babel/core@babel/cli 

核心图书馆

Babel的核心功能位于@ babel / core模块中。安装后:

    npm install --save-dev @babel/core

您可以require直接在JavaScript程序中使用它,如下所示使用它:

const babel = require("@babel/core"); babel.transform("code", optionsObject);

但是,作为最终用户,您可能需要安装其他工具,以作为@babel/core开发过程的界面并与之很好集成。即使这样,您仍可能希望查看其文档页面以了解有关选项的信息,其中大多数选项也可以从其他工具中进行设置。

CLI工具

@ babel / cli是允许您从终端使用babel的工具。这是安装命令和基本用法示例:

npm install --save-dev @babel/core @babel/cli ./node_modules/.bin/babel src --out-dir lib

这将解析目录中的所有JavaScript文件src,应用我们告诉它的所有转换,并将每个文件输出到lib目录。由于我们尚未告诉它应用任何转换,因此输出代码将与输入相同(不保留确切的代码样式)。我们可以通过将其作为选项传递来指定所需的转换。

我们使用了--out-dir上面选项。您可以通过运行来查看cli工具接受的其余选项--help但是现在对我们最重要的是--plugins--presets

插件和预设

转换以插件的形式出现,即小型JavaScript程序,可指导Babel如何进行代码转换。您甚至可以编写自己的插件,以将所需的任何转换应用于代码。要将ES2015 +语法转换为ES5,我们可以依赖于以下官方插件@babel/plugin-transform-arrow-functions

npm install --save-dev @babel/plugin-transform-arrow-functions ./node_modules/.bin/babel src --out-dir lib --plugins=@babel/plugin-transform-arrow-functions

现在,我们代码中的所有箭头函数都将转换为与ES5兼容的函数表达式:

const fn = () => 1; // converted to var fn = function fn() { return 1; };

 

这是一个好的开始!但是我们的代码中还有其他ES2015 +功能需要转换。与其一一添加我们想要的所有插件,我们可以使用“预设”,它只是一组预定的插件。

就像插件一样,您也可以创建自己的预设来共享所需的插件的任意组合。对于我们这里的用例,有一个出色的预设名为env

 

npm install --save-dev @babel/preset-env ./node_modules/.bin/babel src --out-dir lib --presets=@babel/env

没有任何配置,此预设将包括所有插件以支持现代JavaScript(ES2015,ES2016等)。但是预设也可以选择。而不是从终端传递cli和预设选项,让我们看一下传递选项的另一种方式:配置文件。

组态

根据需要,有几种使用配置文件的不同方法。请务必阅读有关如何配置Babel的深入指南,以获取更多信息。

现在,让我们创建一个babel.config.js具有以下内容的文件

 

const presets = [ [ "@babel/env", { targets: { edge: "17", firefox: "60", chrome: "67", safari: "11.1", }, }, ], ]; module.exports = { presets };

 

现在,env预设将仅加载目标浏览器中不提供的功能的转换插件。我们已经准备好语法。接下来让我们看一下polyfills。

Polyfill

Ba从Babel 7.4.0开始,不推荐使用此软件包,而直接包括core-js/stable包括regenerator-runtime/runtimepolyfill ECMAScript功能)和(需要使用转译的生成器函数):

import "core-js/stable"; import "regenerator-runtime/runtime";

@通天塔/填充工具模块,包括核心的JS和一个自定义的再生运行模拟一个完整的ES2015 +环境。

这意味着您可以使用新的内置函数,例如PromiseWeakMap,静态方法Array.fromObject.assign,实例方法Array.prototype.includes以及和生成器函数(与regenerator插件一起使用)。String为了实现此目的,polyfill和本机原型增加了全局范围

对于库/工具作者来说,这可能太多了。如果您不需要这样的实例方法Array.prototype.includes,则可以使用transform runtime插件而不是完全不污染全局范围@babel/polyfill

要更进一步,如果您确切地知道需要哪些功能,可以直接从core-js要求它们

由于我们正在构建应用程序,因此我们可以安装@babel/polyfill

npm install --save @babel/polyfill

请注意该--save选项,而不是--save-dev因为它是需要在源代码之前运行的polyfill。

现在对我们来说幸运的是,我们正在使用env预设,预设具有一个"useBuiltIns"选项,当设置"usage"为时它将实际上应用上面提到的最后一个优化,其中您仅包括所需的polyfills。使用此新选项,配置将如下更改:

      const presets = [ [ "@babel/env", { targets: { edge: "17", firefox: "60", chrome: "67", safari: "11.1", }, useBuiltIns: "usage", }, ], ]; module.exports = { presets };

Babel现在将检查您所有的代码,以查找目标环境中缺少的功能,并且仅包括所需的polyfill。例如此代码:

Promise.resolve().finally();

会变成这样(因为Edge 17没有Promise.prototype.finally):

require("core-js/modules/es.promise.finally"); Promise.resolve().finally();

配置 Babel

Babel 也由配置文件!许多其他工具都有类似的配置文件:ESLint (.eslintrc)、Prettier (.prettierrc)。

所有 Babel API 参数 都可以被配置。然而,如果该参数需要用到 JavaScript 代码,你可能需要使用 JavaScript 代码版的 配置文件

你的使用场景是什么?

            你是否希望以编程的方式创建配置文件?

            你是否希望编译 node_modules 目录下的模块?

    babel.config.js 文件可以满足你的的需求!

          你是否只是需要一个简单的并且只用于单个软件包的配置?

           .babelrc 文件适合你!

          The Guy Fieri is your hero?

         我们建议使用 babel.config.js 格式的配置文件。Babel 本身使用的就是这种

  babel.config.js

         在项目的根目录(package.json 文件所在目录)下创建一个名为 babel.config.js 的文件,并输入如下内容。

        module.exports = function (api) { api.cache(true); const presets = [ ... ]; const plugins = [ ... ]; return { presets, plugins }; }

  .babelrc

        在你的项目中创建名为 .babelrc 的文件,并输入以下内容。

        { "presets": [...], "plugins": [...] }

  package.json

       或者,还可以选择将 .babelrc 中的配置信息作为 babel 键(key)的值添加到 package.json 文件中,如下所示:

        { "name": "my-package", "version": "1.0.0", "babel": { "presets": [ ... ], "plugins": [ ... ], } }

        .babelrc.js

        与 .babelrc 的配置相同,但你可以使用 JavaScript 编写。

       const presets = [ ... ]; const plugins = [ ... ]; module.exports = { presets, plugins };

        你还可以调用 Node.js 的任何 API,例如基于进程环境进行动态配置:

       const presets = [ ... ]; const plugins = [ ... ]; if (process.env["ENV"] === "prod") { plugins.push(...); } module.exports = { presets, plugins };

        使用 CLI (@babel/cli)

       babel --plugins @babel/plugin-transform-arrow-functions script.js

    使用 API (@babel/core)

      require("@babel/core").transform("code", { plugins: ["@babel/plugin-transform-arrow-functions"] });

      学习ES2015

       

es6功能

介绍

ECMAScript 2015是2015年6月批准的ECMAScript标准。

 

ES2015是对该语言的重要更新,也是自2009年对ES5进行标准化以来的第一个主要更新目前,正在主要JavaScript引擎中实现这些功能

有关 ECMAScript 2015语言的完整规范,请参见ES2015标准

ECMAScript 2015功能

箭头和词法

箭头是使用=>语法的功能缩写它们在语法上类似于C#,Java 8和CoffeeScript中的相关功能。它们同时支持表达式和语句主体。与函数不同,箭头this与其周围的代码共享相同的词汇如果箭头在另一个函数内,则它共享其父函数的“参数”变量。

// Expression bodies var odds = evens.map(v => v + 1); var nums = evens.map((v, i) => v + i); // Statement bodies nums.forEach(v => { if (v % 5 === 0) fives.push(v); }); // Lexical this var bob = { _name: "Bob", _friends: [], printFriends() { this._friends.forEach(f => console.log(this._name + " knows " + f)); } }; // Lexical arguments function square() { let example = () => { let numbers = []; for (let number of arguments) { numbers.push(number * number); } return numbers; }; return example(); } square(2, 4, 7.5, 8, 11.5, 21); // returns: [4, 16, 56.25, 64, 132.25, 441]

班级

        ES2015类是基于原型的OO模式的语法糖。具有单个方便的声明形式使类模式更易于使用,并鼓励了互操作性。类支持基于原型的继承,超级调用,实例以及静态方法和构造函数。

class SkinnedMesh extends THREE.Mesh { constructor(geometry, materials) { super(geometry, materials); this.idMatrix = SkinnedMesh.defaultMatrix(); this.bones = []; this.boneMatrices = []; //... } update(camera) { //... super.update(); } static defaultMatrix() { return new THREE.Matrix4(); } }

增强的对象文字

        对象文字被扩展为支持在构造时设置原型,foo: foo分配简写,定义方法和进行超级调用。它们在一起也使对象文字和类声明更加紧密地结合在一起,并使基于对象的设计受益于某些便利。

var obj = { // Sets the prototype. "__proto__" or '__proto__' would also work. __proto__: theProtoObj, // Computed property name does not set prototype or trigger early error for // duplicate __proto__ properties. ['__proto__']: somethingElse, // Shorthand for ‘handler: handler’ handler, // Methods toString() { // Super calls return "d " + super.toString(); }, // Computed (dynamic) property names [ "prop_" + (() => 42)() ]: 42 };

__proto__属性需要本机支持,并且在先前的ECMAScript版本中已弃用。现在,大多数引擎都支持该属性,但有些引擎不支持另外,请注意,仅需要Web浏览器即可实现它,如附件B所示它在Node中可用。

模板字符串

模板字符串为构造字符串提供了语法糖。这类似于Perl,Python等中的字符串插值功能。可选地,可以添加标签以允许对字符串结构进行自定义,从而避免注入攻击或从字符串内容中构建更高级别的数据结构。

// Basic literal string creation `This is a pretty little template string.` // Multiline strings `In ES5 this is not legal.` // Interpolate variable bindings var name = "Bob", time = "today"; `Hello ${name}, how are you ${time}?` // Unescaped template strings String.raw`In ES5 "\n" is a line-feed.` // Construct an HTTP request prefix is used to interpret the replacements and construction GET`http://foo.org/bar?a=${a}&b=${b} Content-Type: application/json X-Credentials: ${credentials} { "foo": ${foo}, "bar": ${bar}}`(myOnReadyStateChangeHandler);

解构

        解构允许使用模式匹配进行绑定,并支持匹配数组和对象。销毁是故障自动处理的,类似于标准对象查找foo["bar"]undefined当找不到时会产生值。          

// list matching var [a, ,b] = [1,2,3]; a === 1; b === 3; // object matching var { op: a, lhs: { op: b }, rhs: c } = getASTNode() // object matching shorthand // binds `op`, `lhs` and `rhs` in scope var {op, lhs, rhs} = getASTNode() // Can be used in parameter position function g({name: x}) { console.log(x); } g({name: 5}) // Fail-soft destructuring var [a] = []; a === undefined; // Fail-soft destructuring with defaults var [a = 1] = []; a === 1; // Destructuring + defaults arguments function r({x, y, w = 10, h = 10}) { return x + y + w + h; } r({x:1, y:2}) === 23

Default + Rest + Spread

      被调用方评估的默认参数值。在函数调用中将数组转换为连续的参数。将尾随参数绑定到数组。休息代替了需求,arguments更直接地解决了常见情况。

function f(x, y=12) { // y is 12 if not passed (or passed as undefined) return x + y; } f(3) == 15

function f(x, ...y) { // y is an Array return x * y.length; } f(3, "hello", true) == 6     

function f(x, y, z) { return x + y + z; } // Pass each elem of array as argument f(...[1,2,3]) == 6

Let + Const

块范围绑定结构。let是新的varconst是单人作业。静态限制会阻止分配前使用。

function f() { { let x; { // this is ok since it's a block scoped name const x = "sneaky"; // error, was just defined with `const` above x = "foo"; } // this is ok since it was declared with `let` x = "bar"; // error, already declared above in this block let x = "inner"; } }

迭代器+ For..Of

迭代器对象启用自定义迭代,例如CLR IEnumerable或Java Iterable。使用泛化for..in为基于定制迭代器的迭代 for..of不需要实现数组即可启用LINQ之类的惰性设计模式。

let fibonacci = { [Symbol.iterator]() { let pre = 0, cur = 1; return { next() { [pre, cur] = [cur, pre + cur]; return { done: false, value: cur } } } } } for (var n of fibonacci) { // truncate the sequence at 1000 if (n > 1000) break; console.log(n); }

迭代基于这些鸭子类型的接口(仅对博览会使用 TypeScript类型语法):

interface IteratorResult { done: boolean; value: any; } interface Iterator { next(): IteratorResult; } interface Iterable { [Symbol.iterator](): Iterator }

通过polyfill提供支持

为了使用Iterators,您必须包括Babel polyfill

发电机

生成器使用function*简化迭代器创作yield声明为function *的函数返回Generator实例。生成器是迭代器的子类型,包括附加nextthrow这些使值可以流回到生成器中,yield返回值(或引发)的表达式形式也是如此

注意:也可以用于启用类似于“ await”的异步编程,另请参见ES7 await proposal

var fibonacci = { [Symbol.iterator]: function*() { var pre = 0, cur = 1; for (;;) { var temp = pre; pre = cur; cur += temp; yield cur; } } } for (var n of fibonacci) { // truncate the sequence at 1000 if (n > 1000) break; console.log(n); }

生成器接口为(仅将TypeScript类型语法用于博览会):

interface Generator extends Iterator { next(value?: any): IteratorResult; throw(exception: any); }

通过polyfill提供支持

为了使用Generators,您必须包括Babel polyfill

统一码

不间断的新增功能可支持完整的Unicode,包括字符串中的新unicode文字形式和u用于处理代码点的新RegExp 模式,以及用于在21位代码点级别处理字符串的新API。这些附加功能支持在JavaScript中构建全局应用。

// same as ES5.1 "𠮷".length == 2 // new RegExp behaviour, opt-in ‘u’ "𠮷".match(/./u)[0].length == 2 // new form "\u{20BB7}" == "𠮷" "𠮷" == "\uD842\uDFB7" // new String ops "𠮷".codePointAt(0) == 0x20BB7 // for-of iterates code points for(var c of "𠮷") { console.log(c); }

模组

     对组件定义模块的语言级别支持。整理来自流行的JavaScript模块加载器(AMD,CommonJS)的模式。由主机定义的默认加载器定义的运行时行为。隐式异步模型–在可用和处理请求的模块之前,不会执行任何代码。

// lib/math.js export function sum(x, y) { return x + y; } export var pi = 3.141593;

// app.js import * as math from "lib/math"; console.log("2π = " + math.sum(math.pi, math.pi));

// otherApp.js import {sum, pi} from "lib/math"; console.log("2π = " + sum(pi, pi));

// lib/mathplusplus.js export * from "lib/math"; export var e = 2.71828182846; export default function(x) { return Math.exp(x); }

// app.js import exp, {pi, e} from "lib/mathplusplus"; console.log("e^π = " + exp(pi));

模块加载器支持:

  • 动态加载
  • 状态隔离
  • 全局名称空间隔离
  • 编译挂钩
  • 嵌套虚拟化

可以配置默认的模块加载器,并且可以构造新的加载器以在隔离或受约束的上下文中评估和加载代码。

// Dynamic loading – ‘System’ is default loader System.import("lib/math").then(function(m) { alert("2π = " + m.sum(m.pi, m.pi)); }); // Create execution sandboxes – new Loaders var loader = new Loader({ global: fixup(window) // replace ‘console.log’ }); loader.eval("console.log(\"hello world!\");"); // Directly manipulate module cache System.get("jquery"); System.set("jquery", Module({$: $})); // WARNING: not yet finalized

需要额外的polyfill

由于Babel默认使用common.js模块,因此它不包括用于模块加载器API的polyfill。在这里得到它 

使用模块加载器

为了使用它,您需要告诉Babel使用 system模块格式化程序。另外一定要签出 System.js

Map + Set + WeakMap + WeakSet

通用算法的高效数据结构。WeakMaps提供了无泄漏的对象键控边表。

// Sets var s = new Set(); s.add("hello").add("goodbye").add("hello"); s.size === 2; s.has("hello") === true; // Maps var m = new Map(); m.set("hello", 42); m.set(s, 34); m.get(s) == 34; // Weak Maps var wm = new WeakMap(); wm.set(s, { extra: 42 }); wm.size === undefined // Weak Sets var ws = new WeakSet(); ws.add({ data: 42 }); // Because the added object has no other references, it will not be held in the set

 

代理人

代理使对象的创建具有可用于宿主对象的全部行为。可以用于拦截,对象虚拟化,日志记录/分析等。

 

// Proxying a normal object var target = {}; var handler = { get: function (receiver, name) { return `Hello, ${name}!`; } }; var p = new Proxy(target, handler); p.world === "Hello, world!";

 

// Proxying a function object var target = function () { return "I am the target"; }; var handler = { apply: function (receiver, ...args) { return "I am the proxy"; } }; var p = new Proxy(target, handler); p() === "I am the proxy";

 

对于所有运行时级别的元操作都有可用的陷阱:

var handler = { // target.prop get: ..., // target.prop = value set: ..., // 'prop' in target has: ..., // delete target.prop deleteProperty: ..., // target(...args) apply: ..., // new target(...args) construct: ..., // Object.getOwnPropertyDescriptor(target, 'prop') getOwnPropertyDescriptor: ..., // Object.defineProperty(target, 'prop', descriptor) defineProperty: ..., // Object.getPrototypeOf(target), Reflect.getPrototypeOf(target), // target.__proto__, object.isPrototypeOf(target), object instanceof target getPrototypeOf: ..., // Object.setPrototypeOf(target), Reflect.setPrototypeOf(target) setPrototypeOf: ..., // for (let i in target) {} enumerate: ..., // Object.keys(target) ownKeys: ..., // Object.preventExtensions(target) preventExtensions: ..., // Object.isExtensible(target) isExtensible :... }

符号

符号启用对对象状态的访问控制。使用符号可以通过string(或在ES5中)或键来键入属性symbol符号是一种新的原始类型。name调试中使用的可选参数-但不是标识的一部分。符号是唯一的(例如gensym),但不是私有的,因为它们通过反射特征暴露出来Object.getOwnPropertySymbols

(function() { // module scoped symbol var key = Symbol("key"); function MyClass(privateData) { this[key] = privateData; } MyClass.prototype = { doStuff: function() { ... this[key] ... } }; // Limited support from Babel, full support requires native implementation. typeof key === "symbol" })(); var c = new MyClass("hello") c["key"] === undefined

通过polyfill提供有限的支持

有限的支持需要Babel polyfill由于语言限制,某些功能无法转译或填充。有关更多详细信息,请参见core.js的警告部分

可细分的内置

在ES2015中,可以将ArrayDate和DOM Element之类的内置子类化。

// User code of Array subclass class MyArray extends Array { constructor(...args) { super(...args); } } var arr = new MyArray(); arr[1] = 12; arr.length == 2

部分支持

内置的子类别性应根据具体情况进行评估,因为诸如类HTMLElement 可以被子类化,而诸如之类可以被子类化DateArray并且Error 不能归因于ES5引擎的限制。

数学+数字+字符串+对象API

增加了许多新的库,包括核心数学库,数组转换助手和用于复制的Object.assign。

Number.EPSILON Number.isInteger(Infinity) // false Number.isNaN("NaN") // false Math.acosh(3) // 1.762747174039086 Math.hypot(3, 4) // 5 Math.imul(Math.pow(2, 32) - 1, Math.pow(2, 32) - 2) // 2 "abcde".includes("cd") // true "abc".repeat(3) // "abcabcabc" Array.from(document.querySelectorAll("*")) // Returns a real Array Array.of(1, 2, 3) // Similar to new Array(...), but without special one-arg behavior [0, 0, 0].fill(7, 1) // [0,7,7] [1,2,3].findIndex(x => x == 2) // 1 ["a", "b", "c"].entries() // iterator [0, "a"], [1,"b"], [2,"c"] ["a", "b", "c"].keys() // iterator 0, 1, 2 ["a", "b", "c"].values() // iterator "a", "b", "c" Object.assign(Point, { origin: new Point(0,0) })

来自polyfill的有限支持

Babel polyfill支持大多数此类API 但是,由于各种原因(例如,String.prototype.normalize需要大量其他代码来支持),某些功能被省略了 您可以在此处找到更多的polyfills 

 

二进制和八进制文字

为二进制(b)和八进制(o添加了两个新的数字文字形式

 

0b111110111 === 503 // true 0o767 === 503 // true

仅支持文字形式

巴别塔只能改变0o767而不是 Number("0o767")

承诺

承诺是用于异步编程的库。承诺是将来可能提供的值的一流表示。在许多现有的JavaScript库中都使用了Promise。

 

function timeout(duration = 0) { return new Promise((resolve, reject) => { setTimeout(resolve, duration); }) } var p = timeout(1000).then(() => { return timeout(2000); }).then(() => { throw new Error("hmm"); }).catch(err => { return Promise.all([timeout(100), timeout(200)]); })

通过polyfill提供支持

为了支持Promises,您必须包括Babel polyfill

反映API

全反射API公开了对象上的运行时级别的元操作。这实际上是代理API的逆,并且允许进行与代理陷阱相同的元操作所对应的调用。对实现代理特别有用。

var O = {a: 1}; Object.defineProperty(O, 'b', {value: 2}); O[Symbol('c')] = 3; Reflect.ownKeys(O); // ['a', 'b', Symbol(c)] function C(a, b){ this.c = a + b; } var instance = Reflect.construct(C, [20, 22]); instance.c; // 42

通过polyfill提供支持

为了使用Reflect API,您必须包含Babel polyfill

尾叫

确保尾部位置的调用不会无限制地增加堆栈。面对无限输入,使递归算法安全。

function factorial(n, acc = 1) { "use strict"; if (n <= 1) return acc; return factorial(n - 1, n * acc); } // Stack overflow in most implementations today, // but safe on arbitrary inputs in ES2015 factorial(100000)

posted @ 2020-01-20 15:35  又回到了起点  阅读(434)  评论(0编辑  收藏  举报