你可能不知道的 ECMAScript 2016 的变化(英译)

作者: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展示组件与容器组件(英译)

原文链接:

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏程序员互动联盟

【答疑解惑】java中static关键字的作用

static方法 static方法一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说,是没有this的,因为它不依附于任何对象,...

2867
来自专栏JetpropelledSnake

Python入门之面向对象编程(四)Python描述器详解

本文分为如下部分 引言——用@property批量使用的例子来引出描述器的功能 描述器的基本理论及简单实例 描述器的调用机制 描述器的细节 实例方法、静态方法和...

3497
来自专栏Java 源码分析

Java面向对象基础

     面向对象一直是一种很流行的思想,他的精髓也就在于他的三大特性:封装,继承和多态。本文就在这三个方面简单的谈一谈Java的面向对象基础。 1.封装:  ...

3215
来自专栏练小习的专栏

js运算符优先级笔记

运算符的优先级决定了表达式中运算执行的先后顺序,优先级高的运算符最先被执行。 下面是一个简单的例子: 3 + 4 * 5 // 计算结果为23 乘法运算符...

1848
来自专栏从流域到海域

Python的闭包(Closure)与惰性计算(Lazy Evaluation)

闭包 在一些语言中,在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包。运行时,一旦外部的 函数被执行,一个闭包就形成...

20610
来自专栏Android机动车

转向Kotlin——高阶函数与Lambda表达式

在调用高阶函数时使用Lambda表达式,可以使调用语法更加简洁,不过要想使用这种调用方式,就需要深入了解Lambda表达式的用法。

543
来自专栏程序员互动联盟

【编程基础】数组和指针为什么不等价?

好多初学C语言的人都认为数组和指针是相等的,在C 语言中对数组和指针的困惑多数都来自这句话。说数组和指针“等价”不表示它们相同, 甚至也不能互换。它的意思是说数...

3668
来自专栏深度学习之tensorflow实战篇

利用python内置函数,快速统计单词在文本中出现的次数

#coding=utf-8 import collections import os with open('str.txt') as file1:#打开文本...

2868
来自专栏小二的折腾日记

day5(面向对象2)

向上转型,向上转型 千万不要出现这样的操作,就是将父类对象转换成子类类型。 我们能转换的是父类应用指向了自己的子类对象时,该引用可以被提升,也可以被强制转换。 ...

371
来自专栏java学习

面试题2(Java 修饰符问题)

编译并运行下面代码,请选择描述正确的项。 public class XiuShiFu{ int i =10; private static float pi=3...

34015

扫码关注云+社区