Define local function in [removed] use var or not?

2019-01-21 12:09发布

问题:

When a local (inner) function is declared in JavaScript, there are two options:

Declaring with var keyword, assigning to the variable:

(function() {
    var innerFunction1 = function() { ... };
    innerFunction1();
}());

Declaring just with the function keyword, without assigning to variable:

(function() {
    function innerFunction2() { ... };
    innerFunction2();
}());

I can see one advantage of the second: the function can be declared below the code which calls it so it is easier to separate private functions from the code actually executed.

Which of them is better and why?

回答1:

Actually there are 3 ways to declare a function:

  1. Function declaration: A Function Declaration defines a named function variable without requiring variable assignment. Function Declarations occur as standalone constructs and cannot be nested within non-function blocks. ex: function innerFunction1 () { };

  2. Function expression:: A Function Expression defines a function as a part of a larger expression syntax (typically a variable assignment). Functions defined via Function Expressions can be named or anonymous:

    a. Using an anonymous function - var innerFunction1 = function() { };

    b. Using a named function - var innerFunction1 = function myInnerFunction () { };

  3. Function constructor: A Function Constructor defines a function dynamically using the Function( ) constructor. Note that the function body is passed to the function as a string argument. var innerFunction1 = new Function (arg1, arg2, ... argN, functionBody)

The third method is not recommended because passing the function body as a string may prevent some JS engine optimizations, and it is prone to errors.

The differences between function declaration and function expression are subtle and you should choose whichever method suits your requirements best.

I use function expression where I need

  1. a singleton function, or
  2. to determine which function to use programmatically (using a named function expression).

Some differences between a function declaration and a function expression are:

  1. Function expressions allow you to assign different functions to the same variable at different points.
  2. A function defined by a function declaration can be used before the function declaration itself (or basically anywhere in the current scope), whereas a function defined by a function expression can only be used after the point it is defined.

Click here to read the detailed comparison of Function Declaration vs Function Expression vs Function Constructor @MDN

Note: A function declaration can be easily turned into a function expression by assigning it to a var.

function foo() {}
alert(foo); // alerted string contains function name "foo"
var bar = foo;
alert(bar); // alerted string still contains function name "foo"

More Reading:

  • http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html
  • http://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/
  • http://msdn.microsoft.com/en-us/library/ie/x844tc74%28v=vs.94%29.aspx
  • http://es5.github.io/#x15.3
  • var functionName = function() {} vs function functionName() {}


回答2:

The two notations are functionally equivalent.

You can assume that:

function a() {}
function b() {}

is interpreted as:

var a, b;
a = function a() {};
b = function b() {};

This is why you don't have to declare- (not define!) before-use. You can reassign functions after you've defined them, just like you would with a variable. Functions get hoisted just like variables, because they are variables (mind=blown? good!).


Declare-before-use

function a() { b(); } // using b before it's declared?
function b() {}

becomes:

var a, b;
a = function a() { b(); }; // nope! b is declared, we're good
b = function b() {};

Redefining a function

function a() { alert("a"); }
a = function b() { alert("b"); }; // that's weird!

becomes:

var a;
a = function a() { alert("a"); };
a = function b() { alert("b"); }; // oh, that looks normal

Declare vs define

Declare is: var x. In English: "I will be using variable x".

Define is: x = 5. In English "Variable x now has the value 5".

Declare-before-use is required and enforced in "use strict". Define-before-use is not required. If your variables are defined in run-time you're good.

So var x = 5 is both a declaration and a definition, as is function a() {}.

Be cautious when naming functions not to override an existing variable:

var a = function () { alert("a"); };
var b = function a() { alert("b"); };
a(); // prints "b"

Lint tools will pick up on this.


When to use which notation?

I would recommend using the function expression notation (var a = function () {}) only when you are reassigned the value of a later on. The function expression then signals to the reader that a is going to get reassigned and that it is intentional.

Another (minor) argument for the function expression notation is a Lint tool like JSLint that might require you to declare (not define!) your functions before you use them. If you have functions with a recursive definition, ie. a calls b and b calls a, you can not declare one before the other by using the function declaration notation.

Edit notes: I've made a slight revision about named anonymous functions. It can be usefull to name anonymous functions when you're looking at a stacktrace. The named function will give more context lest it be logged as 'anonymous'.



回答3:

The difference is that function with VAR is defined at run-time,

whereas function() without VAR is defined at parse-time for a script block.

That is the only major difference..

So, user will decide on the requirement basis, which to use, and which suits the requirement..



回答4:

There is not any difference in output. Both can still be invoked and both can have their prototype accessed by name.

There are only two real differences.

1) Readability and preference

Some people find one way easier to read than others, and they will in turn base their convention on that style. Following convention is important.

2) Slight space saver

With minification being ever more relevant for scripts, you can see how it might be advantageous to use the second approach as it does not require the use of var or = which will save a basically insignificant 4 characters of space in your minified script.


Executive Summary

It all comes down to preference. Which is better? You tell me. Personally, I will use var if I intend to make an object out of it with new and then I will capitalize the first letter, such as Person. Otherwise, I tend to camelCase it and omit the use of var.



回答5:

  • var without function name

    • is better if you master your variable declarations: especially when they are declared.


  • Function named without var:

    • implies a so named variable declaration at the beginning of the current scope and it may prevent from some errors,
    • but: declaring a function this way, using a closure variable declared with var will fail if this function is called before the closure variable is even declared. So, you have to know what you do.


  • Function named with or without var

    • is good for class declaration,
    • and for profiling cause, for instance, Chrome dev profiling tool will be more explicit if functions are not anonymous: they will have an explicit name and you will know where is the slow part of your code.


  • Function named and with var

    • is the way to have the function as a named scope without having the declared variable as a closure
    • while keeping the mastering of variable declaration order.


回答6:

Local declarations should always use var.

Well I would say that first is better since it is a local scope and memory could be cleared after symbol not more in use.

There is also a note on google javascript style guide saying that the second form is not part of standard so it should not be used.

Function Declarations Within Blocks

Do not do this:

if (x) { function foo() {} } While most script engines support Function Declarations within blocks it is not part of ECMAScript (see ECMA-262, clause 13 and 14). Worse implementations are inconsistent with each other and with future EcmaScript proposals. ECMAScript only allows for Function Declarations in the root statement list of a script or function. Instead use a variable initialized with a Function Expression to define a function within a block:

if (x) {

var foo = function() {}

}

Source http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml .



回答7:

Agree with @MarmiK. Also the difference between two methods is the scope. While function declaration assigns local scope by default, the scope of the function assigned to a variable depends on the scope of the variable.

var a;
(function() {
    var innerFunction1 = function() { ... };//local scope
    a=innerFunction1;//assigning to a global variable
}());

can be accessed globally. Go with the function declaration if you dont need to change the scope. https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope

EDIT:

var a;
(function() {
    function innerFunction1() { ... };//local scope
    a=innerFunction1;//It works too(Don't know why it should though)
}());

So, as pointed out by @Frits, there seems to be no scope advantage in using one type over the other.



回答8:

Zakas says that "As long as you always define functions before they used, you can feel free to use either function declarations or function expressions."

It means, if your code will be changed tomorrow by another person you dont know some day, and it is a big project that the developer cant find where the function is declared, you must use function declaration ( i mean function x(){} ), or if you declare the functions first anyway, you can use expressions.



回答9:

I think that everybody who starts programming in JavaScript asks the question to themselves sooner or later. I would reformulate your question to:

Should I use (prefer to use) function declaration (function statement) or function expression (var version)?

In the most cases one can write good JavaScript code using only one from the constructions. It's clear that there are some important differences in semantic, but I want to stress, that in my opinion the answer on the question is mostly the answer about the style of the program. So I would answer that in the most real cases the choice is the matter of the taste.

The persons who prefer to use function statement use it mostly not while they need define readonly function variable and not why they don't want to declare it before it will be used. In my opinion one uses it so mostly because one likes the form.

So I think that there are no objectively correct answer on your question. The choice is subjective. So I write in my answer which construction I personally prefer and in which situations.

My first languages were Pascal, C, Fortran, C++ etc. I used to use C# now. So when I started to write JavaScript programs I used at the beginning my existing style of writing of programs from another languages. Later I changed the style of my JavaScript code corresponds to specific of the language.

I personally prefer to use function expression style and I declare all the functions in the first statement of the outer function. I find that the form mostly clear to JavaScript semantic where the name of the function is variable contains a function value. The name of the function is subject to hoisting like any other variable. For example my code look like below

(function() {
    "use strict";
    var myFunc1 = function (x) {
            // body where I can use x and this
            alert("x=" + x + ", this.foo=" + this.foo);
        },
        localVar1 = {foo: "bar"};

    myFunc1.call(localVar1, 1);
}());

I use function statement very seldom and only if I declare the constructor of the class like:

(function() {
    "use strict";
    function MyClass(x) {
        // the code of constructor
        this.abc = x;
    }
    var myInstance = new MyClass("xyz");
    alert(myInstance.abc);
}());

I try never use the third form:

(function() {
    "use strict";
    var myFunc1 = function myFunc2(x) {
            ...
        };
    ...    
}());

where myFunc2 are declared additionally to myFunc1. The implementation of such form depends from web browser. It has sense probably in case of usage recursive functions.



回答10:

Defining a javascript function

As mentioned by Vega, there are 3 ways of defining a function:

  1. function constructor
  2. function declaration
  3. function expression

Cons of Function constructor:

Function constructors needs the function body as a string which:

  • may prevent some JS engine optimizations
  • makes the syntax incredibly hard to write: need to escape special characters & some other madness, see below

    var foo = (new Function("var bar = \'FOO!\';\nreturn(function() {\n\talert(bar);\n});"))();

    foo(); // The segment "function() {\n\talert(bar);\n}" of the function body string is not re-parsed.

Cons of Function declaration:

It can be invoked before the function declaration itself, this actually introduces complexity:

  • if you do a new function declaration inside another function, how can you reach your new function? see jQuery Document Ready and Function Scope
  • why would a function declaration be invokable before it is defined when the rest of javascript behaves differently?
  • did you know that in the background "a function declaration also creates a variable with the same name as the function name" !?
  • what happens if a variable with the same name as a function declaration is defined before (or after) it?
  • can my function definition still be invoked when I suround it by a pair of brackets ? http://jsbin.com/makipuxaje/1/edit?js,console versus http://jsbin.com/demecidoqu/1/edit?js,console versus http://jsbin.com/xikufakuwo/1/edit?js,console
  • It is very easy to convert function declarations into function expressions, intentionaly... or by mistake, do you understand the consequences? see What does the exclamation mark do before the function? and also JavaScript plus sign in front of function name
  • Javascript function scoping and hoisting
  • Why are my JavaScript function names clashing?

Pros of Function expression:

Function expressions are simpler:

  • you "just know" what variable it is assigned to
  • you cannot invoke/reference the variable to which the function is assigned to before its definition, which is a consistent behavior with the rest of the javascript definitions

More about: Converting function declarations into function expressions

Danger: As mentioned in "Cons of Function declaration" this can lead to many issues, below are more details about this.

It is very easy to convert function declarations into function expressions.

"A function declaration ceases to be one when it either: becomes part of an expression is no longer a "source element" of a function or the script itself. A "source element" is a non-nested statement in the script or a function body"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions#Examples_2

"function statements are subject to hoisting. This means that regardless of where a function is placed, it is moved to the top of the scope in which it is defined. This relaxes the requirement that functions should be declared before used, which I think leads to sloppiness. It also prohibits the use of function statements in if statements. It turns out that most browsers allow function statements in if statements, but they vary in how that should be interpreted. That creates portability problems." - from the book: Javascript The Good Parts


More about function expressions

Syntax is such as:

 var varName = function [name]([param] [, param] [..., param]) {    /* function expression */
      statements
 }

Things to note about [name] (just after "function" in Syntax):

  • The function name can be omitted, in which case the function becomes known as an anonymous function.
  • "A function name cannot be changed, while the variable the function is assigned to can be reassigned."
  • "The function name can be used only within the function's body." , you can use this feature to let the function call itself recursively.

Then using [name] you can do strange/funny things such as below. Note that I do not recommend doing this if you are new to function definitions.

var count = 0;

var varName = function funcName() {    /* function expression */
  console.log('count is: ' + count );
  if(count<1){
    count++;
    funcName();   /* calls function funcName another time  */
  }
};

varName();    // invokes function funcName via variable varName
funcName();   // throws an error as funcName is not reachable

see live demo on jsbin.com/gijamepesu/1/edit?js,console

A typical implementation & usage would be such as below.

 var myCoolFunc = function ( username, firstName, lastName ) {    /* function expression */
      console.log('user ' + username + ' has the real full name ' + firstName + ' ' + lastName);
 }

 myCoolFunc();

Another thing to note: function expressions can be immediately invoked, vs function declarations cannot. This feature is used in IIFE, read more on What is the purpose of wrapping whole Javascript files in anonymous functions like “(function(){ … })()”?


Resources

  • https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope#Function_constructor_vs._function_declaration_vs._function_expression
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions
  • Book: Javascript The Good Parts


回答11:

Short answer: It doesn't matter in the code, but you should put var to make it more readable.

Long answer: Local variables in JavaScript, just like global variables in JavaScript, can be defined with or without var. Therefore, the function of the program will not be interfered by the lack or presence of the word var. Because it is easier to read code with var, it is suggested that you do put var before variables when they are first declared. But if you want it to be unreadable, then you should not put var before defining a variable.