作者:kurtshen

译自The ECMAScript 2016 change you probably don't know, Posted at October 18, 2016 by Nicholas C. Zakas.

与ECMAScript 6(也称为ECMAScript 2015)相比,ECMAScript 2016是对JavaScript语言规范的一个小更新。 这是由于ECMAScript版本现在决定将修订发布的周期变为每年更新,实际上只是已准备好的所有功能的快照。因此,大多数资源仅列出ECMAScript 2016中的两个显着变化:

  • 1.添加乘幂(**)运算符
  • 2.添加Array.prototype.includes()方法

这些功能对JavaScript开发人员具有最直接的影响,但是,还有一个常常被遗忘的重大变化。 这是我在我的书《Understanding ECMAScript 6》中所提到的,但是,我仍然会收到关于它的问题,所以我想深挖一下这个问题。

首先,我将描述变化的内容,然后我将说明变化的内容背后的理由。

变化

ECMAScript 2016说,“use strict”指令不能用于其参数具有默认值的函数的正文中,使用解构或者rest参数。 规范将简单参数定义为仅包含标识符的参数列表(ECMAScript 5仅支持简单参数列表)[1]。 该更改会影响所有函数类型,包括函数声明和表达式,箭头函数和简明对象字面值方法。例如:

// 可以使用
function doSomething(a, b) {
    "use strict";

    // code
}

// 在ECMAScript 2016中为语法错误
function doSomething(a, b=a) {
    "use strict";

    // code
}

// 在ECMAScript 2016中为语法错误
const doSomething = function({a, b}) {
    "use strict";

    // code
};

// 在ECMAScript 2016中为语法错误
const doSomething = (...a) => {
    "use strict";

    // code
};

const obj = {

    // 在ECMAScript 2016中为语法错误
    doSomething({a, b}) {
        "use strict";

        // code
    }
};

你仍可在函数之外全局使用“use strict”,以便该函数在严格模式下运行,即使该函数具有非简单的参数。 例如:

// 可以使用
"use strict";

function doSomething(a, b=a) {
    // code
}

在这种情况下,函数之外的“use strict”指令是有效的语法。 如果你使用ECMAScript模块,这也不是一个问题,它以严格模式运行所有代码。

为什么要有此变化?

由于严格模式和非简单参数列表的工作方式,此更改很重要。当在ECMAScript 5中创建严格模式时,解构和缺省参数值不存在,因此解析参数列表并查看“use strict”指令没有问题。在这一点上,“use strict”不能影响解析参数列表的结果,它只用于验证参数标识符(不允许重复和检查禁用的标识符,如eval和arguments)。然而,随着在ECMAScript 6中引入解构和默认参数值,情况已经不再是这样,因为规范指出参数列表应该按照与函数体相同的模式进行解析(这意味着“use strict”指令在函数体必须触发严格模式)。

首先要意识到的是严格模式需要更改JavaScript代码的解析和执行[2]。作为一个非常简单的例子,strict模式不允许使用旧式八进制数字文字(例如070)。如果代码在严格模式下解析,则070将抛出语法错误。考虑到这一点,你认为以下代码应该做什么?

// 在ECMAScript 2016中为语法错误
function doSomething(value=070) {
    "use strict";

    return value;
}

如果一个JavaScript解析器试图解析此代码,参数列表将会在函数体之前被解析。这意味着070被解析为有效,然后在函数体中遇到“use strict”,它告诉解析器,“实际上,你应该在严格模式下解析参数列表”。 在这一点上,解析器将必须在严格模式下回溯并重新解析参数列表,所以为070抛出语法错误。这可能不是一个大问题,但如果默认参数值更复杂怎么办?

// 在ECMAScript 2016中为语法错误
function doSomething(value=(function() {
   return doSomeCalculation() + 070;
}())) {
    "use strict";

    return value;
}

在这种情况下,使用默认参数值中使用的函数,你会有更多的问题。为了在严格模式下运行,使得必须展开的token数量更多,还必须将该函数设置为默认值。 为了确保默认参数值表达式被正确解析,并理解为运行在严格模式,将变得十分复杂。

解构参数也会导致类似的问题,因为它们可以包含默认值。 例如:

// 在ECMAScript 2016中为语法错误
function doSomething({value=070}) {
    "use strict";

    return value;
}

这里,解构参数值具有在严格模式下不允许的默认值,导致与默认参数值相同的问题。

最后,TC-39决定[3]对于这种在ECMAScript 5中不存在问题的情景中,简单地禁止函数体使用“use strict”,以避免丢失边缘情况。 这意味着具有默认参数值,解构参数或rest参数的函数在函数体中不能有“use strict”。 这包括“use strict”没有效果的情况,例如:

function outer() {
    "use strict";

    // 在ECMAScript 2016中为语法错误
    function doSomething(value=070) {
        "use strict";

        return value;
    }
}

此示例将具有非简单参数的函数嵌套在具有“use strict”的另一个函数中。 doSomething()函数自动处于严格模式,但JavaScript引擎仍会在doSomething()的函数体中的“use strict”指令上抛出语法错误。

解决方法

这种变化不太可能影响许多开发人员,这可能是为什么你不知道它。“use strict”指令开始沦为JavaScript的历史文物,因为ECMAScript模块和类都会以严格模式自动运行,而无需选择退出,这意味着在这些情况下不需要使用“use strict”。 但是,在极少数情况下,你需要一个带有非简单参数的函数在严格模式下运行,你可以使用IIFE立即执行函数的形式创建函数:

const doSomething = (function() {
    "use strict";

    return function(value=42) {
        return value;
    };
}());

在此代码中,在以严格模式运行的IIFE中创建函数。 这允许返回的函数在使用默认参数值的情况下以严格模式运行。 因为外部作用域以严格模式运行,所以毫无疑问可以正确解析默认参数值,并且不需要在函数体内额外添加“use strict”

总结

这个对ECMAScript 2016的小改变,不允许函数体使用非简单参数列表的函数“use strict”,突显了这样一个流行语言在演进过程中的困难重重。 在这种情况下,TC-39决定通过引入一个新的语法错误消除歧义,如果这个问题早点出现,便可能是ECMAScript 6(2015)的一部分。 添加这个语法错误是最显著有效的方式,因为它影响非常少的现有代码(规范更改是在JavaScript引擎实现非简单参数列表的同时进行的),并且可能不会影响很多未来代码,因为ECMAScript模块和类以严格模式运行。

引用

原文链接:http://ivweb.io/topic/582925ea9554d860548c1fa4

相关推荐
ECMAScript 2015 (ES6) in Node.js(译)
[译]Top JavaScript Frameworks & Topics to Learn in 2017
React展示组件与容器组件(英译)

文章来源于腾讯云开发者社区,点击查看原文