سؤال

Is there any performance hit for writing a function such that local var statements are replaced with arguments? Example:

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;
}

Some advantages:

  • smaller minified size: no var statements;
  • less programmer time spent trying to use as few vars as possible
  • all local vars defined in one place

...and disadvantages:

  • arguments can be altered in unexpected ways. See below
  • less clear in body that vars are local
  • confusing to see arguments that don't do anything
  • if someone unknowingly removes them, your code writes to globals

Still it might be an easy way for a minifier to automatically squeeze out more bits.

Update: a big disadvantage not mentioned so far: If a function is called with N parameters, the first N items in arguments will be binded to the first N identifiers in the argument list (see the last bullet in 10.1.8). Consider this:

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

In the above example, if you called processStuff(stuff1, stuff2), setting i and j would overwrite arguments[0] and arguments[1] respectively.

هل كانت مفيدة؟

المحلول

I wouldn't do it for many of the reasons you already know, personally I don't like the fact of mixing the semantic meaning of arguments vs. variables, although at the implementation level, when the function is executed, they are just properties of the current variable object, they have different meaning IMO.

Now, answering the question, I don't think there's any performance impact.

Let me talk a bit about the the Variable Instantiation process, it takes place for Function Code, just before the function is executed (commonly known as "hoisting"), at first, all the Formal Parameters described for the function are bound to the current Variable Object (the current scope), and they are initialized with the values passed in the function call or undefined if not supplied.

After that, all the identifiers that belong to all var statements within the function are declared in the current scope, and initialized with undefined (note that the assignments are made after this, the function body isn't actually being executed yet).

The third step are FunctionDeclarations, all the identifiers of function declarations are bound to the local scope, if an identifier was previously declared, its value is replaced, for example:

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

  function a () {}

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

I would recommend instead simply to use a single var statement, at the top of the function:

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;
}

That doesn't just organize your code, it would help you to prevent unwanted results due the function-only scope of JavaScript and the "hoisting" nature of var, some tools like JSLint encourage this also.

نصائح أخرى

No, don't do this. It's confusing and unnecessary. And I find your list of "advantages" to be quite specious - every item on there is very thin as to the actual benefit gained.

If you must, just use the comma operator and declare all your variables in a single statement right at the head of the function (they're hoisted to this spot anyways.

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

Or you can declare/define all in once step too

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

I think readability and maintainability outweight filesize and microoptimizations here. It is much easier to read code that has the var keyword. Besides that, one var statement per scope should be sufficient (that is where JavaScript hoists them, anyway). All local variables are available everywhere in the local scope (regardless of the order they have been declared). So all local variables should be declared at the same position (at the beginning of the local scope) for best readability. These four bytes for the var statement are really not worth introducing possible bugs by allowing the user to set the initial values of your local variables by calling that function with additional parameters. It breaks encapsulation (you can get this right, but you'll end up with more bytes than you saved by omitting var). Besides that, it is really confusing to anyone that is trying to read your code.

The same advantages you give, can be achieved by just removing the var keyword:

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

There's no need to explicitly write the var keyword, as you are defining all variables in this case with a value ( l = arr.length, total = 0, i = 0 ).

By the way, notice that you cannot predefine variables by defining them as function arguments. This is not possible, for instance:

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

So, I don't think your solution to minify code is very useful after all, as the disadvantages remain ;)


Edit

I didn't think about the fact that defining variables without the var keyword would turn them into globals. That might be something you don't want at all...

But as I think about the problem again, I don't see why you would want to define variables in function arguments. All advantages you give for that method, are basically true for this example too:

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

And this example is even shorter.

Chistian Johansen in "Test-Driven Javascript Development"(2011) states : "In general, the arguments object should only be used when formal parameters cannot solve the problem at hand, because using it comes with a performance price. In fact, merely referencing the object will induce some overhead, indicating that browsers optimize functions that don't use it."

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top