【问题标题】:Why is const throwing an error on multiple runs of the code when inside an if() or try{}catch(e){}?为什么在 if() 或 try{}catch(e){} 内多次运行代码时 const 会引发错误?
【发布时间】:2010-11-11 19:24:59
【问题描述】:

我正在尝试使用const 声明一堆常量。我的问题是在 Firebug 控制台中测试代码会引发错误,抱怨“重新声明 const foo”。

我尝试将其包装在 try{}catch(e){} 块中,但这并没有帮助,甚至在尝试使用以下代码绕过它时(为了清楚起见,发布减去所有 console.info()“调试”调用) 第二次运行还是报错:

if(!chk_constsDeclaredYet) {
  var chk_constsDeclaredYet = true;
  const foo="bar";
}

我的问题是,虽然 const 在 if(){} 中,但当代码第二次“运行”时,为什么还要查看 const foo?

注意:代码将在 firebug javascript 控制台中运行,我想要实现的工作流程是:

  1. 将代码粘贴到firebug控制台
  2. 点击运行(创建常量)
  3. 我在控制台中对代码进行了编辑而不重新加载页面(常量仍然在页面上下文中定义)
  4. 再次点击运行(使用 if(){} 来避免重新声明常量,如果它们已经在之前的运行中声明过)
  5. 从 (3) 重复

萤火虫输出:

//FIRST RUN::
>>> console.group() console.info('--code start--'); ...console.info('--code end--'); console.groupEnd()
--code start--
chk_constsDeclaredYet = undefined
foo = undefined
--if()--
--if() running..--
--end if()--
chk_constsDeclaredYet = true
foo = bar
--code end--

//SECOND RUN::
>>> console.group() console.info('--code start--'); ...console.info('--code end--'); console.groupEnd()
TypeError: redeclaration of const foo { message="redeclaration of const foo", more...}

【问题讨论】:

  • 注意:我并不担心对 const atm 的支持 - 现在只是玩弄/试验,尽管指向哪些浏览器支持它的指示器的指针将不胜感激 =P 如果不是,它'将只是我下一次搜索引擎访问的主题=]
  • developer.mozilla.org/en/JavaScript/Reference/Statements/const 在 Firefox 中,部分支持 Opera 和 Safari(可能还有 Chrome),但不支持 IE
  • @Šime Vidas 谢谢,我看到了,但不太明白“部分支持”的确切含义 =P
  • 是的,我也喜欢它说部分支持。基本上,这意味着你必须自己测试:)
  • @Šime Vidas bleurgh testing.. ;) 也许稍后但我现在 cba (只是被动的'哦,我想知道这是否适用于 chrome/opera 用户脚本'的想法.. 不重要完全 =]

标签: javascript firebug constants


【解决方案1】:

这是一个古老的答案。我写了一个slightly newer answer 处理类似的“const 重新分配/范围”问题,其中我表明产生的错误(如果有)因执行方法浏览器而异。

由于const(不是 ECMAScript 第 5 版标准的一部分)在 ECMAScript 第 6 版中具有不同的含义,我建议在当前代码中避免使用它。


const,就像var 一样是“函数范围的”。我怀疑问题是由与var 发生的绑定 上相同类型的“到函数顶部”提升引起的(这解释了为什么异常不是来自赋值,但来自声明)。也就是说,任何后续的const x = ...无论它们出现在哪里,都被认为是无效的,因为之前的声明已经存在(根据定义,每个范围只能有一个给定名称的 const )。但是,const 可以采用任何值,因此 assignment 发生在 const x = ... 站点,就像分配发生在 var x = ... 站点一样,即使注释/绑定被提升为范围的顶部。

这是一个简单的测试用例,可以更清楚地说明问题:

function x () { if (true) { const a = 1 } else { const a = 2 }}
// => TypeError: redeclaration of const a @ <x-jsd:interactive-session

如您所见,错误发生在函数声明时,而发生在函数执行时。这就是为什么 try/catch 不起作用的原因。行为也可能受到您正在处理的交互式工具的影响,具体取决于它执行代码的方式(例如,每次都是相同的执行上下文?)。

但是,这很好用并且强化了上面的初始命题:

(function x() { if (false) { const c = 1 }; return c })()
// => undefined

来自https://developer.mozilla.org/en/JavaScript/Reference/Statements/const

(加粗强调)

创建一个常量,该常量对于声明它的函数来说可以是全局的或局部的。 常量遵循与变量相同的范围规则。

常量的值不能通过重新赋值来改变,常量不能重新声明。因此,虽然可以不初始化就声明一个常量,但这样做是没有用的。

常量不能与同一范围内的函数或变量共享其名称。

const 是 Mozilla 特有的扩展,它不受 IE 支持,但从 9.0 版和 Safari 开始部分被 Opera 支持。

【讨论】:

    【解决方案2】:

    const 类型应始终等于一个常量值。如果if 语句可以更改常量的值,它可能应该是var,因为它的值可以变化。

    但是您遇到的问题似乎是因为您将常量的值设置了两次。您在代码第一次运行时初始化常量。由于该常量在再次运行时具有值,因此您会遇到异常。如果您将const foo = 'bar'; 移动到脚本的顶部,您将不会看到该问题。但同样,如果您希望根据逻辑更改该值,您将需要 var

    编辑

    如果您阅读异常消息,它会显示“重新声明 const foo”。这意味着您不能两次声明 foo 。现在在控制台中,每次运行代码(不刷新),之前的变量仍然在作用域内。因此,理论上,即使您在代码中只看到一次 const foo ,您也会多次声明它。您不能将其包装在 if/else 块中,因为它仍然需要 const foo = 'bar',这仍然是非法声明。

    您可能不得不在运行更改的代码之间刷新页面。

    【讨论】:

    • @Steve Hansell 我想你误解了——这个想法是只在尚未声明的情况下声明常量,NOT 根据逻辑更改值..也许if(!foo) { const foo = 'bar'; } else { /*do nothing because foo is already around */ } 让我的意图更清楚?
    • 我明白,但如果不能设置它仍然不是一个常数。但除此之外,我在 JS 中使用常量的次数不多,这可能是提升的问题。所以即使你在 if 块中声明了 const,它实际上已经被提升到了它的函数的顶部。
    • 如果你声明一个 const foo;然后尝试给它一个值,它仍然会抛出异常。给常量赋值的唯一方法是用 const foo = 'bar' 声明它。如果你写 foo = 'bar',你实际上是在创建一个全局变量,而不是分配给同名的常量。
    • 要么我误解了你,要么你似乎仍然不明白我想要实现的目标.. nb:代码将在 firebug javascript 控制台中运行 .. 我想要实现的工作流程是 1)将代码粘贴到 firebug 控制台 2)点击运行(创建常量) 3)我在控制台中编辑代码而不重新加载页面(常量仍然在页面上下文中定义) 4)再次点击运行(使用 if(){} 以避免重新声明常量,如果它们已经被上一次运行声明)5)从 (3) 重复...
    【解决方案3】:

    我不知道这是否是最好的方法,但eval 会让你解决这个问题:

    if( !chk_constsDeclaredYet ){ eval("const foo = \"bar\"") }
    

    【讨论】:

    • 谢谢 - 没有考虑过这个选项,但我仍然会继续避免 eval() 像瘟疫一样,除非出现其他问题,否则只使用 var ;)
    猜你喜欢
    • 1970-01-01
    • 2018-03-04
    • 2012-11-15
    • 1970-01-01
    • 2016-06-06
    • 1970-01-01
    • 1970-01-01
    • 2020-03-25
    • 1970-01-01
    相关资源
    最近更新 更多