为什么Babel不能正确处理const?

时间:2018-02-05 02:27:08

标签: javascript ecmascript-6 const babeljs

检查下面的代码。计数器声明为const。当你运行它时,它不应该允许它在任何情况下改变!

function increment(counter) {
 counter += 1; 
}

function test() {
    const counter = 1;
    increment(counter);
}

转换后,会生成以下代码。这允许const计数器递增!

function increment(counter) {
  counter += 1; // Counter is declared const, still it can be changed!
}

function test() {
  var counter = 1;
  increment(counter);
}

我只是想了解,无论是Babel转换还是JavaScript规范都存在问题。

修改 我知道,与ES6不同,当前版本的JS不支持const。我担心的是,如果我使用已编译的JavaScript,我可能会遇到未知的const相关错误。那可以吗?

2 个答案:

答案 0 :(得分:8)

  

计数器被声明为const,仍然可以更改!

在转换后的代码中有两个名称为counter的标识符:

  • counter内的参数 increment
  • counter内的变量 test

他们是完全独立的!

参数从不"常量",始终可以为它们分配新值。它对传递给函数的内容没有影响,因为所有参数都是通过值传递,即increment传递变量的 counter,然后将其分配到参数 counter

我们可以通过在函数调用之前和之后记录变量的值来轻松验证这一点:



function increment(counter) {
 counter += 1; 
}

function test() {
    var counter = 1;
    console.log('value before', counter);
    increment(counter);
    console.log('value after', counter);
}

test();




  

我只想了解Babel转换或JavaScript规范是否存在问题

两者都没有。无论您是使用var还是const来声明counter,它都能完全指定。

  

我担心的是,如果我使用已编译的JavaScript,我可能会遇到与const相关的未知错误。

不,那不是这样的。是什么让const特别?您无法为其分配新值并且它被阻止作用域。因此,让我们来看看Babel在违反这两个限制时所做的事情:

输入:

const foo = 21;
foo = 42;

Babel输出:

Babel拒绝使用错误

来转换代码
SyntaxError: intput.js: "foo" is read-only
  1 | const foo = 42;
> 2 | foo = 21;
    | ^
  3 |

输入:

{
  const foo = 21;
}
console.log(foo); // trying to access const outside of block

Babel输出:

"use strict";

{
  var _foo = 21;
}
console.log(foo); // trying to access const outside of block

Babel重命名了块范围的变量。 foo不存在(如预期的那样)。

答案 1 :(得分:0)

这里有两件事:

  1. 该函数传递变量的value而不是变量本身(正如其他答案所解释的那样)
  2. babel将const转换为var并仍然保持不可重新分配合同的方式。我将在答案中解释这一部分:
  3. 为什么Babel没有正确处理const?

    关于babel和const的事情是,它只能通过静态分析工作

    工作代码的转换会将const转换为var,因为ES5中存在所有内容。

    const a = 0
    const b = a + 1;
    // becomes
    var a = 0;
    var b = a + 1;
    

    当babel发现你为你的变量分配不同的值时会发生魔力:

    const a = 1;
    a = a + 1;
    // becomes
    function _readOnlyError(name) { throw new Error("\"" + name + "\" is read-only"); }
    
    var a = 1;
    a = (_readOnlyError("a"), a + 1);
    

    因为babel可以告诉它会通过读取代码引发错误,它会替换错误发生时的错误点。

    因此,99%的情况下,const会在转换为ES5时阻止重新分配。

    Ergo Babel正确处理const

    您的代码未被转换为抛出错误的原因是因为第1部分。