Functional JavaScript: Harnessing the power of the Function Object [con't]
Function Scope Primer
Used properly, function scope, like any variable, can enhance security and
protect variables from being changed unintentionally. Conversely, misunderstanding
the rules of scoping in JavaScript, and you could have some really cryptic and
evasive bugs on your hands! Any functions defined at the <SCRIPT>
level
are global, and are accessible to every function, object and sub-function, regardless
of their location in the code. Functions defined inside another function
are trickier because the scope depends on how we define the inner function.
At the beginning of the article we saw two ways of defining a function:
var fn = function() {}
and function fn() {}
. There are a couple more options
that we haven't seen yet. The last one, using the Function()
constructor,
doesn't affect scoping, so we'll leave that for later. It's the fn = function()
{}
syntax that can cause trouble. Whereas both the methods described earlier
will create private variables when defined within another function, dropping
the var
keyword will always result in the creation of a global function, no matter
where it's defined. The cause of this quirky behavior is that the var
keyword
is optional. Omitting it will cause the scripting engine to create the variable
and add it to the global
window
object. Ergo: the var identifier is important! The following code snippet
demonstrates the finer points of function scoping:
What is Lambda?
The concept of using a function as an argument in a function call is called lambda. Lambda derives from Lambda calculus and is a formal system designed to investigate function definition, function application and recursion. Developed in the 1930's, Lambda has emerged as a useful tool in the investigation of problems in computability or recursion theory, and forms the basis for Functional Programming. Functional programs are stateless and deal exclusively with functions that accept and return data (including other functions), but they produce no side effects in 'state' and make no alterations to incoming data.
The Function Object
It's important to keep in mind that a function in JavaScript isn't just a
variable type, but a full-fledged object. In fact, all native JavaScript data
types have equivalent objects, which store their properties and methods. For
instance, when we create a string using the following syntax: var aString =
"This is a string."
, a String
object is automatically created behind
the scenes. This allows us to check its length using aString.length
or call a method such as aString.split(', ');
on it. In addition to having properties
and methods, each object has at least one constructor. In the case of a String
,
we could also create one in the following manner: var myString = new String("This
is a string object")
.
Function
object also has a constructor: new Function(string arguments,
string body)
. Here's how we would create the testFor()
function via the constructor:
The arguments parameter must consist of a comma-delimited list of valid JavaScript
identifiers. In this case there's only one argument called "fn."
The
body is also a string containing all of the function code contained within
the function block's opening and closing curly braces ({}
).
Generally, using the Function
's constructor to define functions should be kept
to a minimum because it's generally slower than using one of the means that
we discussed previously. Still, there are times where it may be appropriate
to create one on the fly. We'll be looking at just such a situation in the "Self
Invoking Function" section.
Function Properties
arguments: An array of all the arguments passed to a function.
arguments.callee: Returns a reference to the current function. Can only be used within the body of a function.
arguments.length: Returns the number of arguments passed to a function.
constructor: Specifies the function that creates an object's prototype. It's a direct reference to the function itself.
length: Specifies the number of arguments expected by a function. It's external to the function and not the same as the arguments.length property, which specifies the number of arguments actually passed to a function.
prototype: A value from which all instances of an object are constructed, and which also allows you to add other properties and methods to an object.
Function Methods
apply: Allows you to pass function arguments and the this pointer to another function.
call: Allows you to call a method within a different context.
toSource/toString/valueOf: All three methods return a string representing the source code of the function. They override their respective Object methods.
The following code uses the arguments.length and Function.length properties to compare the number of expected arguments to the number actually received. An error is thrown if they don't match: