如何检查ES6“;变量“;是恒定的

How to check that ES6 "variable" is constant?

本文关键字:变量 ES6 何检查 检查      更新时间:2023-09-26

有人知道怎么做吗?我尝试使用try-catch:

"use strict";
const a = 20;
var isConst = false;
try {
   var temp = a; a = a+1; a = temp;
} catch (e) {
   isConst = true;
}

但不幸的是,它只能在"严格"模式下工作。在不使用"use strict"的情况下,它以静默方式执行所有语句,而不修改a。此外,我无法将此代码封装到某个方便的函数(例如isConstant(someConst))中,因为我将传递给该函数的任何参数都将是一个新变量。那么有人知道如何创建isConstant()函数吗?

我认为没有,但我也不认为这是一个大问题。我认为知道一个变量是否是const可能会很有用,这在其他一些语言中也存在,但实际上,由于你(或团队中的某个人)将定义这些变量,你会知道变量的范围和类型。换句话说,不,你不能,但这也不是问题。

唯一有用的情况是,您是否可以在运行时更改mutable属性,以及更改此属性是否具有实际的性能优势;letconstvar对编译器的处理大致相同,唯一的区别是编译器会跟踪const,并在编译之前检查赋值。

另一件需要注意的事情是,就像let一样,const的作用域是当前作用域,所以如果你有这样的东西:

'use strict';
const a = 12;
// another scope
{
  const a = 13;
}

它是有效的。只要小心,如果你没有在新的作用域中显式地声明const a = 13,它会在更高的作用域内查找,并且它会给出Read OnlyAssignment错误:

'use strict';
const a = 12;
{
  a = 13; // will result in error
}

基于这里的一些答案,我写了这个代码片段(用于客户端JS),它将告诉您如何;变量";是最后一次宣布的——我希望它有用。

使用以下内容来找出x最后声明为什么(取消注释x的声明以测试它):

// x = 0
// var x = 0
// let x = 0
// const x = 0
const varName = "x"    
console.log(`Declaration of ${varName} was...`)
try {
  eval(`${varName}`)
  try {
    eval(`var ${varName}`);
    console.log("... last made with var")
  } catch (error) {
    try {
      eval(`${varName} = ${varName}`)
      console.log("... last made with let")
    } catch (error) {
      console.log("... last made with const")
    }
  }
} catch (error) {
  console.log("... not found. Undeclared.")
}

有趣的是,在没有varletconst(即x = 0)的情况下声明会导致默认使用var。此外,函数参数是使用var在函数作用域中重新声明的。

只需检查您的重新分配是否真的做了什么:

var isConst = function(name, context) {
  // does this thing even exist in context?
  context = context || this;
  if(typeof context[name] === "undefined") return false;
  // if it does exist, a reassignment should fail, either
  // because of a throw, or because reassignment does nothing.
  try {
    var _a = context[name];
    context[name] = !context[name];
    if (context[name] === _a) return true;
    // make sure to restore after testing!
    context[name] = _a;
  } catch(e) { return true; }
  return false;
}.bind(this);

您需要try/catch,因为重新分配可能会引发异常(如在Firefox中),但如果没有(如在Chrome中),您只需检查您的"这总是改变值"重新分配是否真的做了任何事情。

一个简单的测试:

const a = 4;
var b = "lol";
isConst('a'); // -> true
isConst('b'); // -> false

如果您在不同的上下文中声明常量,则传入该上下文以强制解析正确的对象。

缺点:这对在对象作用域之外声明的vars不起作用。好处是:在其他地方声明它们是完全没有意义的。例如,在函数范围中声明它们会使const关键字基本上毫无用处:

function add(a) {
  return ++a;
}
function test() {
  const a = 4;
  console.log(add(a));
}
test(); // -> 5

尽管a在test()中是常量,但如果将其传递给其他任何对象,它将作为一个常规可变值传递,因为它现在只是arguments列表中的"一件事"。

此外,拥有const的唯一原因是它不会改变。因此,不断地重新创建它,因为你调用了一个多次使用它的函数,这意味着你的const应该位于函数之外,所以我们不得不再次将变量放在对象范围中。

这个问题指的是早期ES6实现中的不一致行为,尤其是V8(Node.js 4和遗留Chrome版本)。这个问题在现代ES6实现中并不存在,无论是在严格模式下还是在草率模式下。const的重新分配应该总是导致TypeError,它可以被try..catch捕获

不能有isConstant函数,因为const变量不能通过其值来识别。

最好在严格模式下运行脚本,从而避免草率模式特有的问题。

即使变量是以草率模式定义的,也可以在嵌套函数范围中启用严格模式:

const foo = 1;
// ...
let isConst = false;
(() => {
  'use strict';
  try {
    const oldValue = foo;
    foo = 'new value';
    foo = oldValue;
  } catch (err) {
     isConst = true;
  }
})();

使用在JavaScript和其他语言中使用的UPPERCASE_CONSTANT约定是有益的。它允许在没有IDE帮助的情况下明确地将变量标识为常量,并避免意外重新分配的大多数问题。