What is return function used for in JavaScript
I have this incredibly simple example that works without return function and fails with it:
function hello() {
alert('hello');
}
function hi() {
return function() {
alert('hi');
}
}
I know that by doing hi()();
I am 开发者_JAVA百科able to run the second function but I rarely ever see this in code. How can I do return function without doing that as I see people do that all the time.
The return function can cache some variables from the first invoked function, and then you can do something later on the return function.
For example,
function hi(lastName) {
return function(firstName) {
alert('hi ' + firstName + lastName);
}
}
var chen = hi("Chen");
chen("Jumper");
chen("Dennis");
To make the best of it you'll have to put together three things: Data-Types, Function-Execution (or invocation in some sources), and Scope & Closure.
I'll try to put here the simplest perspective:
First - you need to understand is the issue of returned-values and Data-Types in JavaScript.
Any expression in JavaScript evaluates to one of the following data-types, and be part of another expressions for further computing (where the most common to my observation is assign into a variable, the next common is returned as function's returned value):
number
, string
, boolean
, object
, undefined
- and - function
.
(there are also some pseudo types - like Infinity
and NaN
, but leave it now, google it later).
Every expression in JavaScript has a returned value. every expression. Really. Sometimes the value is simply undefined
- but that's also a returned value. However, saying that every expression have a returned value - That includes definitions of functions. There is not much difference between:
function foo(){}
and
foo = function(){}
(and to keep the answer useful, I'll avoid discussing the difference between the two forms).
This leads to the next subject - execution of functions in JavaScript.
In the example above, the returned value is a function reference, that you can later execute using the ()
operator. Yes - operator. the ()
is an operator that executes the code behind the reference while providing it an argument stack with the values provided in the ()
.
In that sence, after declaring the foo
function and keeping it available on the variable foo
- you can later call foo()
as much as you like - that is because foo
is a variable that holds a reference to the function, which can be later executed - as long as the variable foo
is not overriden with another value or hidden by a more local variable in that name.
To emphasize: calling foo()
is first evaluating what foo
means, and then operating it as function with empty arguments stack (because it's foo()
, and not just foo
)
In that sence, you can evaluate what foo()
is, and then operate it as a function - like in your original example foo()()
. You know what? you can go on in this: foo()()()
, and foo()()()
, however - mind that you will get an exeption once the evaluated expression you're trying to operate ()
on is not a function reference.
That's why you can see codes like
obj[ handler ](42);
or worse
obj[ getHandlerName(handler) ] (42);
(to keep short I'll explain only the first) - which will first evaluate what obj
is, then assume it's an object and evaluate obj[ handler ]
, then assume it's a function and try to execute it as obj[ handler ](42)
- passing it 42 as single argument. Note that handler is a variable name, that can contain any value, where in this sense it will be tried as string (or use the return value of it's toString() method - because [] is also an operator, but that's a subject for a different post).
This arguments stack is implied by the execution of the function, and there is no limitation about the number or the types of the arguments provided to function and the number and types the function actually expects.
All arguments passed to a function during execution is accessible using the implied argument arguments
, that is a pseudo-array construct - best described simply as arguments stack...
Why pseudo? It does not answer to any of the APIs that Array provides, except the property length
, and the indexer access (i.e arguments[0], arguments[1], and so on).
A function may define variable names for the arguments it expects to work with, and these will correspond to arguments[n]
in accord to the 0-index place in the arguments variable names.
Now, if a function is a data-type, it can be returned and executed later. In that sence, there is not much differene between
function a(){
return function b(){}
}
and
function a(){
function b(){}
return b; //pay attention - no braces = don't execute b, return the func-ref.
}
and
function a(){
var b = function(){}
return b;
}
Actually, the last here is considered to be dirty, and the next issue will help you understand why.
Second thing - Scope and closure.
In JavaScript, scope of variables is the function in which they are defined. (It's confusing for programmers that come from other languages where variables are limited to the block they are defined in - this limit does not apply to JavaScript. The blocks that have meanings for purpose of scope are only function-bodies).
In that sense, the top-most level, AKA "root", or "main" - is the highest level, where globals are defined. This means that variables and functions that are defined on the root are accessible to all of the codes that are executed, and therefore act as globals.
Closure is when execution of a function defines inside it other functions, and "publicates" one or more of them - ither by assigning them to a global variable, or by returning a function reference, that is later kept by the code that invoked the defining function on the first place.
Now, since as explained above - every execution of a function defines at least one variable called arguments
- in addition to the argument variable-names it is defined with - the argument-variable names are accessible to any code of any function that is defined in it - or defined by execution of function that is defined in it (or defined by execution of a function that is defined by execution of a function that is defined with it, or defined by execution of a ... well, you got the point).
This means that:
var G = "global"
function a(x,y){
var h = "local to closure a"
, z = function(){
var k = "local to this function"
//code here can access G
//code here can access k
// - and x and y - and - h and z!
}
;
return z;
}
And that opens space for very interesting usages - like a callback function that can access local variables that hold a private state defined by the arguments passed to a while retrieving callback z from it.
I hope it puts some things together simply enough :)
Self executing and callback functions are both pretty common approaches.
Find working samples here: http://jsfiddle.net/ezmilhouse/9BbGC/
// self executing
function hi( text ) {
return (function(text) {
alert(text);
})(text);
}
hi('ho');
// callback
function ho(callback){
callback();
}
ho(function(){
alert('ha');
});
精彩评论