【问题标题】:V8 engine compiler bug report [duplicate]V8引擎编译器错误报告[重复]
【发布时间】:2020-09-29 12:27:41
【问题描述】:

今天,当我在编写代码时,在没有分号的对象定义的右大括号之后立即编写时,解构赋值将无法正常工作。 如果您看到相同的结果,请您从头开始重新创建此错误并报告。
我的节点版本是 12.16.2
我也在 Github 上报告了这个错误,用于 V8 引擎和 Nodejs

https://github.com/v8/v8.dev/issues/482#issue-711046361

https://github.com/nodejs/nodejs.org/issues/3411#issue-711047377

不带分号的对象的右大括号

let a,b,c
a={x:1} //<~~~without semicolon
[b, c] = [1, 2]
console.log(b)
console.log(c)

以上代码将返回

undefined
undefined

用分号定义的对象的大括号

let a,b,c
a={x:1}; //<~~~with semicolon
[b, c] = [1, 2]
console.log(b)
console.log(c)

以上代码将返回

1
2

if 语句的大括号

let a,b,c
if(1===1){
  a = 1
} //<~~~without semicolon
[b, c] = [1, 2]
console.log(b)
console.log(c)

以上代码将返回

1
2

【问题讨论】:

    标签: node.js compiler-errors v8


    【解决方案1】:

    首先,报告 V8 错误的正确位置是 crbug.com/v8/new。 StackOverflow 不适合报告错误。

    其次,这不是错误;它是 JavaScript 的“自动分号插入”,按规定工作。您可以阅读规范here。归结为 a = {x:1}[b, c] = [1, 2] 是有效的 JavaScript(可能是荒谬的,但语法有效),因此不会自动插入分号。

    避免落入此类陷阱和类似陷阱的最佳方法是始终编写明确的分号。或者您可能更喜欢无分号代码的视觉简洁性,但是您必须熟悉 ASI 的规则,并知道在哪些情况下需要分号。

    编辑:既然你在下面问a = {x:1}[b, c] = [1, 2] 做了什么,这里有一个解释:

    首先,您可以链接赋值,例如x = y = z = 0;,因此该表达式的一个效果是变量a 之后将指向数组[1, 2]。 看看中间词{x:1}[b, c],前半部分当然是一个对象字面量。后半部分是一个索引表达式,用于访问该对象的属性。作为简化版本,请考虑:{x:1}["x"] 将返回 1。 (注意:如果您在例如控制台中对此进行评估,则必须将对象文字包装到(),即({x:1})["x"],因为否则{} 将被解释为块而不是文字。其中之一JavaScript的许多陷阱...) 现在这里的具体索引表达式是b, c,它是一个逗号分隔的表达式序列,类似于你可以写成for (x = 0, y = 0; ...; ...) {...}。因此,b 部分会评估副作用;因为它只是对变量的引用,所以没有任何作用,但你可以例如在那里写console.log(b) 然后它会做一些事情。 c 则是序列的整体结果值;在您的示例中,它是一个未初始化的变量,因此它的值为undefined,在索引表达式的上下文中它被转换为字符串"undefined"

    将所有内容放在一起,按顺序排列如下:

    1. [1, 2] 被评估并创建一个二元素数组。让我们将此数组称为 A,仅用于描述目的。
    2. {x:1} 被评估并创建一个具有 x 属性的对象。让我们将此对象称为O,再次仅出于描述目的。
    3. b 被评估(到undefined),评估结果被丢弃。
    4. c 被评估(到undefined),转换为字符串"undefined",并用于将A 作为属性存储在O 上,就像在O["undefined"] = A 中一样,或者就像你写了{x:1, undefined:[1, 2]} .
    5. 由于没有任何东西引用O,因此它变得无法访问并且有资格进行垃圾收集。你看不到它发生了第 (4) 步。
    6. A 将分配给 a

    总而言之,a = {x:1}[b, c] = [1, 2] 肯定是一段奇怪的代码,但如果 JavaScript 引擎为你决定“我确定你的意思是别的,让我给你一个行为,我认为你想要”。只要您编写有效的 JavaScript,引擎必须根据 JavaScript 语言的规则准确评估它。

    【讨论】:

    • 哦,原来实际的顺序有点不同:[b, c][1, 2] 之前被评估。但是在这个例子中并没有改变任何东西,可以说我上面使用的顺序有点简单,可以理解发生了什么。
    • 您对表达式a = {x:1}[b, c] = [1, 2] 将如何编译 的描述是正确的,我同意您的观点,但您完全错过了主要问题。首先,请注意我的示例表达式是用两行单独编写的,如果您检查 link,主要规则之一是 违规标记与前一个标记至少有一个 LineTerminator 分隔 那么我们期望该Javascript解释器将两行表达式转换为a = {x:1};[b, c] = [1, 2],而不是将它们混合为一行中的一个表达式。
    • 似乎 JavaScript 解释器 ASI 将错过在 a = {x:1} 表达式之后插入分号,因为它紧跟在下一行中的左括号并且左括号被解释为上一行对象文字的索引, 无论如何这是不正确的行为。在我看来,问题出在 V8 实现或 JavaScript 规则并不重要,因为解释器如何工作或编译器从开发人员的角度编译代码都无关紧要。开发者需要使用无分号的 JavaScript 编程语言正确编写和运行代码。
    • 请注意规范中句子的开头:当从左到右解析源文本时,遇到任何语法生成都不允许的标记,. ..。换句话说:只有在没有分号的情况下才会插入分号,否则会出现语法错误。你引用的是一个额外的限制:分号只能自动插入到行尾(不能在行中间)。
    【解决方案2】:

    是的,我知道这是 Javascript 解释器的 ASI 行为,但这是不可接受的,在我看来,这是一个应该修复的错误。
    编程语言提供无分号语法并给程序员留下不需要的和不正确的行为和陷阱,这是不合逻辑的,也是绝对不能接受的。
    我们程序员已经了解到,每个编程表达式都是“具有绝对唯一结果的句法实体”而不是陷阱。
    我们开发软件,而不是玩编程语言决定为我们设置陷阱的 Jumanji 游戏。
    是的,下面的语法是有效的,请作为程序员仔细阅读下面的代码:

    a = {x:1}[b, c] = [1, 2]
    

    您对运行此代码有何期望? 我希望 Javascript 将“{x:1}”设置为“a”变量,将“1”、“2”设置为“b”和“c”变量。
    最后我不明白为什么解释器会犯这个错误?

    a = {x:1}
    

    在这一行解释器中,正确地看到以左大括号开始并以右大括号结束的对象,然后 ASI 可以在右大括号后插入分号,并且不要将其与下一个表达式混淆

    [b, c] = [1, 2]
    

    如果我错了,请纠正我。

    【讨论】:

    • JavaScript 有很多奇怪的地方,但是按照语言规范的规则实现语言的引擎并不是 bug,相反:如果 V8 做了什么不同的事情,那么 将是一个错误。
    • 我已经修改了我的答案,详细解释了 a = {x:1}[b, c] = [1, 2] 的作用和原因。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-28
    • 2016-08-23
    相关资源
    最近更新 更多