4

我一直在考虑 javascript 编程风格,我想知道添加一些语法糖来防止使用隐式全局容易犯的错误是否有意义,即:

var OuterFunction = function() { // closure container
    var renamedCounter = 0; // someone renamed counter,
    this.resetCounter = function () {
        counter = 0; // ... but forgot to check the inner functions as well.
        return this;
    };
    return this;
}

在这个例子中, counter 突然变成了一个全局变量,而不是一个局部作用域为OuterFunction.

通过“声明”一个闭包捕获的变量void,您可以获得一个自由断言,就像任何其他使用counter但未分配给它的代码一样。

this.resetCounter = function () {
    void counter; // this will throw an Error if counter is not in scope.
    counter = 0;
    return this;
};

编辑:正如jleedev指出的那样,仅使用变量名本身似乎可以测试它是否存在,即

this.resetCounter = function () {
    counter;
    counter = 0;
    return this;
};

也可以。

我看到的优点是:

  • 写的很短。
  • 在某种程度上,它看起来像一个变量声明。
  • 编辑添加:如果始终如一地完成,语法检查器(肉类或程序)很容易发现此类错误。

另一方面:

  • 这很令人困惑。代码实际上并没有任何事情。
  • 未来的解释器可能会发现它是毫无意义的、无副作用的代码,然后将其优化掉。

有什么我忽略的方面吗?这是一个愚蠢的想法,还是至少有点站得住脚?

提问者的编辑:这应该是一个社区 wiki 问题,但我没有看到将其更改为该复选框的复选框。我隐约记得有一个。

编辑为大愚蠢:当然,+=尝试在递增之前检索表达式的值。因此将示例重命名为resetCounter而不是incrementCounter,这样它就有点意义了。

4

2 回答 2

3

根据ECMASCript 语言规范

11.4.2void运营商

产生式 UnaryExpression : void UnaryExpression 的评估如下:

  1. 令 expr 为计算 UnaryExpression 的结果。
  2. 调用 GetValue(expr)。
  3. 返回未定义。

注意 GetValue 必须被调用,即使它的值没有被使用,因为它可能有明显的副作用。

所以它永远不应该被优化掉。

然而,恕我直言,它看起来不像“声明”一个变量,当然也不像一个变量,所以应该避免。

编辑:确实不应该精确地使用它,因为 GetValue 调用可能会产生副作用,例如,如果变量实际上是一个带有“getter”的属性。

于 2011-03-12T18:41:46.950 回答
1

不确定这是否是您问题的答案,但 ECMAScript 5引入了严格模式,它可以防止隐式全局声明:

分配给未声明的标识符或其他无法解析的引用不会在全局对象中创建属性。当在严格模式代码中发生简单赋值时,其LeftHandSide不得评估为不可解析的引用。如果它确实抛出ReferenceError异常(8.7.2)。LeftHandSide 也可能不是对具有属性值 {[[Writable]]: false } 的数据属性的引用,对具有属性值 {[[Set]]: undefined } 的访问器属性的引用,也不是对不存在的其 [[Extensible]] 内部属性值为false的对象的属性。在这些情况下,会引发 TypeError异常(11.13.1)。

在支持它的浏览器中(目前似乎只有 Firefox 4),您可以使用以下命令激活严格模式

"use strict";

在开发过程中,我使用JSLint检查我的文件是否存在错误或有问题的代码。它会通知您隐含的​​全局变量。

于 2011-03-12T19:16:17.040 回答