Anda di halaman 1dari 6

8/11/2015

Function Declarations vs. FunctionExpressions | JavaScript, JavaScript...

Function Declarations vs. FunctionExpressions


Lets start with a short quiz. What is alerted in each case?:
Question 1:
1
2
3
4
5
6
7
8
9
10

functionfoo(){
functionbar(){
return3
}
returnbar()
functionbar(){
return8
}
}
alert(foo())

Question 2:
1
2
3
4
5
6
7
8
9
10

functionfoo(){
varbar=function(){
return3
}
returnbar()
varbar=function(){
return8
}
}
alert(foo())

Question 3:
1
2
3
4
5
6
7
8
9
10

alert(foo())
functionfoo(){
varbar=function(){
return3
}
returnbar()
varbar=function(){
return8
}
}

Question 4:
1
2
3
4
5
6
7
8
9
10

functionfoo(){
returnbar()
varbar=function(){
return3
}
varbar=function(){
return8
}
}
alert(foo())

If you didnt answer 8, 3, 3 and [Type Error: bar is not a function] respectively, read on (actually read on
anyway

data:text/html;charset=utf-8,%3Cheader%20class%3D%22entry-header%22%20style%3D%22display%3A%20block%3B%20col

1/6

8/11/2015

Function Declarations vs. FunctionExpressions | JavaScript, JavaScript...

What is a 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.
Its helpful to think of them as siblings of Variable Declarations. Just as Variable Declarations must start
with var, Function Declarations must begin with function.
e.g.
1
2
3

functionbar(){
return3
}

ECMA 5 (13.0) defines the syntax as


functionIdentifier(FormalParameterListopt) {FunctionBody}
The function name is visible within its scope and the scope of its parent (which is good because
otherwise it would be unreachable)
1
2
3
4
5
6

functionbar(){
return3
}

bar()//3
bar//function

What is a Function Expression?


A Function Expression defines a function as a part of a larger expression syntax (typically a variable
assignment ). Functions defined via Functions Expressions can be named or anonymous. Function
Expressions must not start with function (hence the parentheses around the self invoking example
below)
e.g.
1
2
3
4
5
6
7
8
9
10
11
12
13
14

//anonymousfunctionexpression
vara=function(){
return3
}

//namedfunctionexpression
vara=functionbar(){
return3
}

//selfinvokingfunctionexpression
(functionsayHello(){
alert("hello!")
})()

ECMA 5 (13.0) defines the syntax as


functionIdentifieropt(FormalParameterListopt) {FunctionBody}
(though this feels incomplete since it omits the requirement that the containing syntax be an expression
and not start with function)
data:text/html;charset=utf-8,%3Cheader%20class%3D%22entry-header%22%20style%3D%22display%3A%20block%3B%20col

2/6

8/11/2015

Function Declarations vs. FunctionExpressions | JavaScript, JavaScript...

The function name (if any) is not visible outside of its scope (contrast with Function Declarations).
So whats a Function Statement?
Its sometimes just a pseudonym for a Function Declaration. However askangaxpointed out, in mozilla a
Function Statement is an extension of Function Declaration allowing the Function Declaration syntax to
be used anywhere a statement is allowed. Its as yet non standard so not recommended for production
development
About that quiz.care to explain?
OK so Question 1 uses function declarations which means they get hoisted
Wait, whats Hoisting?
To quoteBen Cherrys excellent article: Function declarations and function variables are always moved
(hoisted) to the top of their JavaScript scope by the JavaScript interpreter.
When a function declaration is hoisted the entire function body is lifted with it, so after the interpreter
has finished with the code in Question 1 it runs more like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14

//**SimulatedprocessingsequenceforQuestion1**
functionfoo(){
//definebaronce
functionbar(){
return3
}
//redefineit
functionbar(){
return8
}
//returnitsinvocation
returnbar()//8
}
alert(foo())

Butbutwe were always taught that code after the return statement is unreachable
In JavaScript execution there is Context (which ECMA 5 breaks into LexicalEnvironment,
VariableEnvironment and ThisBinding) and Process (a set of statements to be invoked in sequence).
Declarations contribute to the VariableEnvironment when the execution scope is entered. They are
distinct from Statements (such asreturn) and are not subject to their rules of process.
Do Function Expressions get Hoisted too?
That depends on the expression. Lets look at the first expression in Question 2:
1
2
3

varbar=function(){
return3
}

The left hand side (var bar) is a Variable Declaration. Variable Declarations get hoisted but their
data:text/html;charset=utf-8,%3Cheader%20class%3D%22entry-header%22%20style%3D%22display%3A%20block%3B%20col

3/6

8/11/2015

Function Declarations vs. FunctionExpressions | JavaScript, JavaScript...

Assignment Expressions dont. So whenbaris hoisted the interpreter initially setsvar bar = undefined.
The function definition itself is not hoisted.
(ECMA 5 12.2 A variable with aninitialzieris assigned the value of itsAssignmentExpressionwhen
theVariableStatementis executed, not when the variable is created.)
Thus the code in Question 2 runs in a more intuitive sequence:
1
2
3
4
5
6
7
8
9
10
11
12
13
14

//**SimulatedprocessingsequenceforQuestion2**
functionfoo(){
//adeclarationforeachfunctionexpression
varbar=undefined
varbar=undefined
//firstFunctionExpressionisexecuted
bar=function(){
return3
}
//FunctioncreatedbyfirstFunctionExpressionisinvoked
returnbar()
//secondFunctionExpressionunreachable
}
alert(foo())//3

Ok I think that makes sense. By the way, youre wrong about Question 3. I ran it in Firebug and
got an error
Try saving it in an HTML file and running it over Firefox. Or run it in IE8, Chrome or Safari consoles.
Apparently the Firebug console does not practice function hoisting when it runs in its global scope
(which is actually not global but a special Firebug scope try running this == window in the Firebug
console).
Question 3 is based on similar logic to Question 1. This time it is thefoofunction that gets hoisted.
Now Question 4 seems easy. No function hoisting here
Almost. If there were no hoisting at all, the TypeError would be bar not defined and not bar not a
function. Theres no function hoisting, however thereisvariable hoisting. Thusbargets declared up
front but its value is not defined. Everything else runs to order.
1
2
3
4
5
6
7
8
9

//**SimulatedprocessingsequenceforQuestion4**
functionfoo(){
//adeclarationforeachfunctionexpression
varbar=undefined
varbar=undefined
returnbar()//TypeError:"barnotdefined"
//neitherFunctionExpressionisreached
}
alert(foo())

What else should I watch out for?


Function Declarations are officially prohibited within non-function blocks (such as if) . However all
browsers allow them and interpret them in different ways.
data:text/html;charset=utf-8,%3Cheader%20class%3D%22entry-header%22%20style%3D%22display%3A%20block%3B%20col

4/6

8/11/2015

Function Declarations vs. FunctionExpressions | JavaScript, JavaScript...

For example the following code snippet in Firefox 3.6 throws an error because it interprets the Function
Declaration as a Function Statement (see above) so x is not defined. However in IE8, Chrome 5 and Safari
5 the function x is returned (as expected with standard Function Declarations).
1
2
3
4
5
6
7

functionfoo(){
if(false){
functionx(){}
}
returnx
}
alert(foo())

I can see how using Function Declarations can cause confusion but are there any benefits?
Well you could argue that Function Declarations are forgiving if you try to use a function before it is
declared, hoisting fixes the order and the function gets called without mishap. But that kind of
forgiveness does not encourage tight coding and in the long run is probably more likely to promote
surprises than prevent them. After all, programmers arrange their statements in a particular sequence
for a reason.
And there are other reasons to favour Function Expressions?
How did you guess?
a) Function Declarations feel like they were intended to mimic Java style method declarations but Java
methods are very different animals. In JavaScript functions are living objects with values. Java methods
are just metadata storage. Both the following snippets define functions but only the Function Expression
suggests that we are creating an object.
1
2
3
4

//FunctionDeclaration
functionadd(a,b){returna+b}
//FunctionExpression
varadd=function(a,b){returna+b}

b) Function Expressions are more versatile. A Function Declaration can only exist as a statement in
isolation. All it can do is create an object variable parented by its current scope. In contrast a Function
Expression (by definition) is part of a larger construct. If you want to create an anonymous function or
assign a function to a prototype or as a property of some other object you need a Function Expression.
Whenever you create a new function using a high order application such ascurryorcomposeyou are
using a Function Expression. Function Expressions and Functional Programming are inseparable.
1
2

//FunctionExpression
varsayHello=alert.curry("hello!")

Do Function Expressions have any drawbacks?


Typically functions created by Function Expressions are unnamed. For instance the following function is
anonymous,todayis just a reference to an unnamed function:
1

vartoday=function(){returnnewDate()}

Does this really matter? Mostly it doesnt, but asNick Fitzgeraldhas pointed out debugging with
data:text/html;charset=utf-8,%3Cheader%20class%3D%22entry-header%22%20style%3D%22display%3A%20block%3B%20col

5/6

8/11/2015

Function Declarations vs. FunctionExpressions | JavaScript, JavaScript...

anonymous functions can be frustrating. He suggests using Named Function Expressions (NFEs) as a
workaround:
1

vartoday=functiontoday(){returnnewDate()}

However as Asen Bozhilov points out (and Kangaxdocuments) NFEs do not work correctly in IE < 9
Conclusions?
Badly placed Function Declarations are misleading and there are few (if any) situations where you cant
use a Function Expression assigned to a variable instead. However if you must use Function
Declarations, it will minimize confusion if you place them at the top of the scope to which they belong. I
would never place a Function Declarations in anifstatement.
Having said all this you may well find yourself in situations where it makes sense to use a Function
Declaration. Thats fine. Slavish adherance to rules is dangerous and often results in tortuous code.
Much more important is that you understand the concepts so that you can make your own informed
decisions. I hope this article helps in that regard.
Comments are very welcome. Please let me know if you feel anything Ive said is incorrect or if you have
something to add.

data:text/html;charset=utf-8,%3Cheader%20class%3D%22entry-header%22%20style%3D%22display%3A%20block%3B%20col

6/6

Anda mungkin juga menyukai