6

编写一个将本地var语句替换为参数的函数是否会影响性能?例子:

function howManyMatch(arr, pattern, /*ignored:*/ i, l, total) {
  l = arr.length;
  total = 0;
  for (i = 0, i < l; i++) {
    if (pattern.test(arr[i]))
      total++;
  return total;
}

一些优点:

  • 较小的缩小尺寸:没有var声明;
  • 减少程序员花费在尝试使用尽可能少var的 s 上的时间
  • 在一个地方定义的所有本地变量

...和缺点:

  • arguments可以以意想不到的方式改变。见下文
  • 在正文中不太清楚 vars 是本地的
  • 困惑地看到无用的论点
  • 如果有人在不知不觉中删除了它们,您的代码将写入全局变量

仍然可能是缩小器自动挤出更多位的简单方法。

更新:到目前为止没有提到的一个很大的缺点:如果使用 N 个参数调用函数,则其中的前 N ​​个项目arguments将绑定到参数列表中的前 N ​​个标识符(参见10.1.8 中的最后一个项目符号)。考虑一下:

function processStuff(/*ignored:*/i, j, k) {
    // use i/j/k to loop
    // do stuff with the arguments pseudo-array
}

在上面的例子中,如果你调用processStuff(stuff1, stuff2),设置ij将分别覆盖arguments[0]arguments[1]

4

5 回答 5

5

不,不要这样做。这是令人困惑和不必要的。而且我发现您列出的“优势”清单非常似是而非-那里的每一项对于获得的实际收益都非常薄。

如果必须,只需使用逗号运算符并在函数开头的单个语句中声明所有变量(无论如何它们都被提升到这个位置。

function howManyMatch(arr, pattern) {
  var i, l, total;
  // rest
}

或者您也可以一次性声明/定义所有内容

function howManyMatch(arr, pattern) {
  var l = arr.length, total = 0, i = 0;
  // rest
}
于 2010-12-06T21:15:00.373 回答
4

由于您已经知道的许多原因,我不会这样做,我个人不喜欢混合参数与变量的语义含义的事实,尽管在实现级别,当函数执行时,它们只是属性对于当前变量对象,它们在 IMO 中具有不同的含义。

现在,回答这个问题,我认为没有任何性能影响

先说一下变量实例化的过程,它发生在函数代码中,就在函数执行之前(俗称“提升”),首先,为函数描述的所有形式参数都绑定到当前变量对象(当前作用域),它们使用函数调用中传递的值或未undefined提供的值进行初始化。

之后,属于var函数内所有语句的所有标识符都在当前范围内声明,并初始化为undefined(注意,在此之后进行赋值,函数体实际上还没有被执行)。

第三步是 FunctionDeclarations,函数声明的所有标识符都绑定到本地作用域,如果之前声明了标识符,则替换其值,例如:

(function (a) {
  return typeof a; // "function", not "string"

  function a () {}

})('foo');  // <-- passing a string

我建议只var在函数顶部使用单个语句:

function howManyMatch(arr, pattern) {
  var l = arr.length,
      total = 0, i;
  for (i = 0, i < l; i++) {
    if pattern.test(arr[i]) && total++;
  return total;
}

这不仅可以组织您的代码,还可以帮助您防止由于 JavaScript 的仅限函数范围和“提升”性质而导致的不想要的结果, JSLintvar等一些工具也鼓励这样做。

于 2010-12-06T21:15:16.567 回答
1

我认为可读性和可维护性比文件大小和微优化更重要。阅读具有关键字的代码要容易得多。var除此之外,var每个范围一个语句就足够了(无论如何,这就是 JavaScript 提升它们的地方)。所有局部变量在局部范围内的任何地方都可用无论它们被声明的顺序如何)。因此,所有局部变量都应声明在同一位置(在局部范围的开头)以获得最佳可读性。语句的这四个字节var真的不值得通过允许用户设置局部变量的初始值来引入可能的错误通过使用附加参数调用该函数。它破坏了封装(你可以做到这一点,但你最终会得到比你通过省略节省更多的字节var)。除此之外,任何试图阅读您的代码的人都会感到困惑。

于 2010-12-06T21:15:19.497 回答
0

您提供的相同优势可以通过删除var关键字来实现:

function howManyMatch(arr, pattern) {
  l = arr.length;
  total = 0;
  for (i = 0; i < l; i++) {
    if pattern.test(arr[i]) && total++;
  return total;
}

无需显式编写关键字,因为在这种情况下您将使用值 ( , , )var定义所有变量。l = arr.lengthtotal = 0i = 0

顺便说一句,请注意您不能通过将变量定义为函数参数来预定义它们。这是不可能的,例如:

function howManyMatch(arr, pattern, i=0, l, total = 0){ ... }

所以,我认为你缩小代码的解决方案毕竟不是很有用,因为缺点仍然存在;)


编辑

我没有想到在没有var关键字的情况下定义变量会将它们变成全局变量。这可能是你根本不想要的东西......

但是当我再次考虑这个问题时,我不明白为什么要在函数参数中定义变量。您为该方法提供的所有优点对于此示例也基本上是正确的:

function howManyMatch(arr, pattern) {
  var l = arr.length, total = 0, i=0;
  for (; i < l; i++) {
    if pattern.test(arr[i]) && total++;
  return total;
}

这个例子甚至更短。

于 2010-12-06T21:00:40.887 回答
0

Chistian Johansen 在“Test-Driven Javascript Development”(2011)中指出:“一般来说,arguments 对象应该只在形参不能解决手头问题的情况下使用,因为使用它会带来性能代价。事实上,仅仅引用该对象会产生一些开销,表明浏览器会优化不使用它的功能。”

于 2012-06-14T14:22:44.513 回答