简体   繁体   中英

what's correct: var declaration if undefined

I have heard different opinions about the usage of var at a situation like this:

function(maybeUndefined) {
    if(typeof maybeUndefined === 'undefined')
        var maybeUndefined = 'bob';
}

Is it necessary to notate var , or not, because maybeUndefined is an argument of function ?

You do not need the var in this case, as mayBeUndefined is already allocated within the scope of the function (hint: listing argument variables in a function definition causes those variables to be declared locally). That var is therefore completely optional, though completely pointless (and a drain on readability).

Example:

function func ( arg1, arg2 ) {
    var local1, local2;

    function nested1 () {}
    function nested2 () {}

    // other code
}

Here we have a function declaration. When this declaration is parsed into a function object, a lexical environment (= scope) is created for that function with the following bindings:

  • arg1
  • arg2
  • local1
  • local2
  • nested1
  • nested2
  • this
  • arguments

(Notice how there also are two special, built-in bindings: this and arguments . These are always created for all function objects.)

These names are defined as local bindings. (This process is specified in "Declaration binding instantiation" . Warning: this algorithm is not meant to be read by humans :-) ) Therefore, when a name is defined as a parameter, it is not necessary to declare it as a local variable. This mechanism is independent of whether a value (argument) is passed for that parameter when the function is invoked.

So, even if you invoke the function like so:

func(123);

the name arg2 will still be defined (as a binding in the function's environment), although its value will initially be undefined for that particular invocation.

Btw, if you use the strict language (recommended!), function environments are static which means that the above bindings are garanteed to be the only bindings in the function's environment. The default language , on the other hand, provides certain mechanisms to, dynamically , add/remove bindings from the function's environment. Example:

(function () {

    // the name "temp" does not exist as a binding in the function's environment

    eval('var temp');

    // now it does

    delete temp;

    // and it's gone again

}());

You should not use var again, it is bad for readability, and the variable will already be scoped locally as a result of being an argument.

Also, you should note that it is not a part of this . this will only be scoped to the function object if the new keyword has been used, and as you do not have a named function, that seems unlikely in this case. Without new, this refers to window (or is undefined if use strict; is used), of which your variable is definitely not a part of as a result of the argument having a local scope.

Interfacing

Including a function argument is effectively the same as scoping a variable (in other words, it's effectively the same thing as defining a function-level reference using the var keyword). The main reason for providing function arguments (in JavaScript) is for your own interfacing preference.

The arguments object

Arguments may still be passed to functions without parameters, and will still be accessible in the 'hidden' arguments object -- which is sort of a "pseudo-array" (if you will), in that it is functionally an array, but is not equipped with the same APIs JavaScript equips the Array (pseudo-type) with:

// The following functions do the same thing, but one is "more readable"

function foo() {
  return arguments;
}

function bar(baz, qux) {
  return arguments;
}

Evaluation (interface) vs Execution (implement)

When both functions are evaluated (on file 'load'), the arguments object is undefined in every function definition; the object doesn't become "defined" until the function body executes the code therein; to visualize that using pseudo-code, it'd look something like this:

// Function bodies (as objects)
foo : {
  arguments : new Array // [undefined]
  __proto__ : Empty() // the super-object that allows this object to inherit "functionality"
}

bar : {
  arguments : new Array(baz, qux) // [undefined, undefined]
  __proto__ : Empty()
}

Function invocation

So when you invoke a function, it "implements" or "executes" its body (its "object"). When it does that, if the objects that have been pushed into the arguments object are defined, then the function can reference them. If not, a reference error will be thrown, logging that the variables are undefined in that scope.

In short:

It isn't necessary to interface function-scope-level variables (aka "private members") using var because the language already attaches the arguments object to all function body objects.

More reading:

JavaScript Memoization: "Function-caching" multiple arguments for better performance: http://decodize.com/javascript/javascript-memoization-caching-results-for-better-performance/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM