Chapter 6. Building Reusability with JavaScript Functions
6.0. Introduction
JavaScript functions provide a way to encapsulate a block of code in
order to reuse the code several times. They’re typically created using the
function
statement and syntax similar to the following:
function functionname(arg1, arg2, ..., argn) { function body }
JavaScript functions have Function
objects, which can be constructed the same as a String
or Number
, using the new
operator:
var fn = new Function (arg1, arg2, ..., argn, functionbody);
However, using this syntax is not as efficient as using the function
statement, because using a function
constructor requires that the function be parsed each time it’s called.
Functions defined with the function
statement are parsed once, when the code is loaded.
There are three basic kinds of functions:
- Declarative function
A declarative function is a statement triggered by the use of the function keyword, and parsed when the JavaScript application is first loaded.
- Anonymous function or function constructor
An anonymous function is constructed using the new operator and referencing the
Function
object. It’s anonymous because it isn’t given a name, and access to the function occurs through a variable or another object property. It’s parsed each time it’s accessed.- Function literal or function expression
As with other JavaScript objects, functions can be both object and literal. A literal function is a function expression, including parameter and body, which is used in place—such as in an argument to another function. Like a declarative function, it’s also parsed only once, when the JavaScript application is loaded. Like the function created as an object, it can also be anonymous.
6.1. Creating a Block of Reusable Code
Solution
Create a simple, named, parameter-less function using the function
statement:
function simpleFunction() { alert("Hello, function!"); }; simpleFunction();
Discussion
A function created using the function
keyword and
given a name is known as both a declarative
function and a static function. The
basic structure is:
function functionName() { // JavaScript statements }
This type of function is parsed when the page containing the JavaScript application is loaded, and the parsed results are used whenever the function name is referenced. It’s an efficient way of reusing the same code.
Any name that would be valid for a variable would work for a function. Variable names can be any combination of characters, numbers, and underscores, as long as the variable name starts with a character or underscore and case-sensitivity is preserved.
However, functions typically perform some action, and best
practices suggest that the function name should be descriptive. For
instance, a function that sums the numbers in an HTML table might be
named sumTableValues
.
6.2. Passing Single Data Values to and from a Function
Solution
Provide arguments for the incoming data, and return the result:
function makeHello(strName) { return ("Hello " + strName); } window.onload=function() { var name = prompt("What's your name?",""); var greeting = makeHello(name); alert(greeting); }
Discussion
Function arguments are a way to pass data to a function. The arguments are separated by commas and included in the parentheses following the function name:
var firstName = "Shelley": var lastName = "Powers"; makeHello(firstName, lastName);
The function then processes the arguments, as needed:
function makeHello(firstName, lastName) { alert("Hello " + firstName + " " + lastName); }
Data is returned from the function to the calling program using
the return
statement:
function makeHello(firstName, lastName) { return "Hello " + firstName + " " + lastName; }
You can pass several arguments to the function, but only one return value. If you want to return more than one value, you can pass more complex objects, such as an array, to and from a function.
Unless you’re sure about the type of data coming from the user, you’ll want to also test the data first. For instance, if you want to ensure that a value passed to the function is a number, you could do the following:
function someFunc(num) { if (typeof num == "number") { ... } }
You also don’t have to provide a one-to-one mapping between the
value passed to the object, and the number of function parameters. Every
function has an arguments
object which
contains all of the arguments passed to the function. It’s not a true
function, but you can use array index notation to access the argument,
and it does provide a length property for the number of
arguments:
function sumNums() { var sum = 0; for (var i = 0; i < arguments.length; i++) { var num = parseFloat(arguments[i]); if (!isNaN(num)) { sum+=num; } } return sum; } ... var sum = sumNums(4.55, 3.0,1, "apple", 56.33);
See Also
Recipe 6.3 demonstrates passing more complex objects as arguments.
6.3. Passing Complex Data Objects to a Function
Solution
You can use objects, such as arrays, as function arguments:
function makeHello(name) { name[name.length] = "Hello " + name[0] + " " + name[1]; } var name = new Array('Ima','Reader'); makeHello(name); alert(name[2]); // displays "Hello Ima Reader"
Discussion
Function arguments in JavaScript can be scalar values, such as a string or number, or complex objects, such as arrays. Arrays are a simple way to pass many values to a function without having to create separate parameters for each. It’s also a way to pass an unknown number of values to a function, such as an array of numbers to be summed:
function addNumbers(nums) { var total = 0; for (var i = 0; i < nums.length; i++) { total+=nums[i]; } return total; }
A complex object is treated differently than a scalar argument in
a function. In the solution, an array is passed to the
makeHello
function, but isn’t returned from
the function. However, the generated value added to the array in the
function is still accessible to the calling program, because objects are
passed into functions by reference.
Scalar arguments are passed by value, which means that a copy of the argument is made for processing in the function and changes to the argument in the function won’t be reflected back to the calling program. Objects, though, are passed by reference: any changes to them in the function are reflected in the calling program.
Example 6-1 demonstrates the differences between scalar and complex objects when used as function arguments. The function takes two parameters, a string literal and an array. Both are modified in the function, and the contents of both are printed after the function returns control to the calling program.
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Function test</title> <script> //<![CDATA[ window.onload=function() { var items = new Array('apple','orange','cherry','lime'); var sep = '*'; concatenateString(items,sep); alert(items); alert(sep); } function concatenateString(strings, separator) { var result=""; for (var i = 0; i < strings.length; i++) { result+=strings[i] + separator; } // assign result to separator separator = result; // and array strings[strings.length]=result; } //--><!]]> </script> </head> <body> </body> </html>
The array reflects the change that occurred in the function:
apple,orange,cherry,lime,apple*orange*cherry*lime*
While the string argument does not reflect the change, and
consists only of the asterisk separator string (*
).
6.4. Creating a Dynamic Runtime Function
Solution
Use an anonymous function, created using the Function
object constructor:
// two parameters and one function body string var functionName = new Function (x, y, functionBody); functionName(varA, varB); // two parameters are processed by function
Discussion
Functions created using the new Function
object constructor are called
anonymous functions because they’re
not given a function name when they’re created. Instead, they’re
assigned to a variable. You then use the variable as you would a
function call.
Anonymous functions are parsed at runtime, which makes them inefficient for general purposes. However, they allow us to define both parameters and function body at runtime, which is handy if you’re not sure what the function body is going to be until runtime.
To demonstrate an anonymous function, I’m going to borrow an example from another of my books, Learning JavaScript (O’Reilly), replicated in Example 6-2. This JavaScript application prompts the web page reader to provide a function that takes two parameters, as well as the value of the parameters. The application then uses these values to create the function and invoke it.
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Anonymous Function</title> <script> //<![CDATA[ window.onload=function() { var func = prompt("Enter function body:",""); var x = prompt("Enter value for x:",""); var y = prompt("Enter value for y:",""); var newFun = new Function("x","y",func); var result = newFun(x,y); } //--><!]]> </script> </head> <body> </body> </html>
When prompted for the function body, use something simple such as this (shown in Figure 6-1):
alert(x + " " + y)
If you pass in Hello
and
World
for the next two prompts, the result is
an alert message with “Hello World”.
The function return value is assigned a variable, just in case the dynamic function body returns a value. If no value is returned, then the returned value is undefined.
Of course, using an anonymous function like this isn’t the safest thing to do, because you can’t control what the person enters as function body. And it’s not particularly useful either.
Anonymous functions can be useful when passing functions as arguments, or assigning them to object properties. However, in most of these cases a literal function is preferred over a function object, because function literals are parsed once, when the application is loaded.
See Also
Literal functions are covered in Recipe 6.5.
6.5. Passing a Function As an Argument to Another Function
Solution
For the following function:
function otherFunction(x,y,z) { x(y,z); }
use a literal function:
var param = function(arg1, arg2) { alert(arg1 + " " + arg2); }; otherFunction(param, "Hello", "World");
or a function expression as a function argument:
otherFunction(function(arg1,arg2) { alert(arg1 + ' ' + arg2); }, "Hello","World");
Discussion
The function
keyword is an
operator as well as a statement, and can be used to create a function as
an expression. Functions created this way are called function
expressions, function literals, and
anonymous functions, though “anonymous functions”
is an overloaded term since it applies to functions as objects, as well
as functions as expressions.
A function name can be provided with literal functions, but it’s only accessible within the function:
var param = function inner() { return typeof inner; } alert(param()); // prints out "function"
This functionality may not seem useful, but it’s essential if you want to implement recursion.
You can pass a function as an argument to another function as a named variable, or even directly within the argument list, as shown in the solution. Unlike functions constructed as objects, function literals are parsed when the page is loaded, rather than each time they’re accessed.
See Also
See Recipe 6.6 for a demonstration of using a named function literal in recursion.
6.6. Implementing a Recursive Algorithm
Problem
You want to implement a function that will recursively traverse an array and return a reversed array string.
Solution
Use a function literal recursively until the end goal is met:
var reverseArray = function(x,indx,str) { return indx == 0 ? str : reverseArray(x,--indx,(str+= " " + x[indx]));; } var arr = new Array('apple','orange','peach','lime'); var str = reverseArray(arr,arr.length,""); alert(str); var arr2 = ['car','boat','sun','computer']; str = reverseArray(arr2,arr2.length,""); alert(str);
Discussion
Before looking at the solution, I want to cover the concept of recursion first, and the look at functional recursion.
Recursion is a well-known concept in the field of mathematics, as well as computer science. An example of recursion in mathematics is the Fibonacci Sequence:
fn = fn-1 + fn-2, for n= 2,3,4,...,n and f0 = 0 and f1 = 1 |
A Fibonacci number is the sum of the two previous Fibonacci numbers.
Another example of mathematical recursion is a factorial, usually denoted with an exclamation point (4!). A factorial is the product of all integers from 1 to a given number n. If n is 4, then the factorial (4!) would be:
24 = 1 × 2 × 3 × 4 |
These recursions can be coded in JavaScript using functional recursion. A common example of JavaScript recursion is the solution for a Fibonacci:
var fibonacci = function (n) { return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2); }
or a factorial:
function Factorial(n) { return n == 1 ? 1 : n * Factorial(n -1); } var val = Factorial(4);
In the Fibonacci example, n is tested to see if it is less than 2. If it is, the value of n (2) is returned; otherwise the Fibonacci function is called again with (n – 1) and with (n – 2), and the sum of both is returned.
A little convoluted? The second example with the Factorial
might be clearer. In this example,
when the function is first called, the value passed as argument is
compared to the number 1. If n is less than or
equal to 1, the function terminates, returning 1.
However, if n is greater than 1, what’s
returned is the value of n times a call to the
Factorial
function again, this time
passing in a value of n – 1. The value of
n, then, decreases with each iteration of the
function, until the terminating condition (or base) is reached.
What happens is that the interim values of the function call are pushed onto a stack in memory and kept until the termination condition is met. Then the values are popped from memory and returned, in a state similar to the following:
return 1; | // 0! |
return 1; | // 1! |
return 1 * 2; | // 2! |
return 1 * 2 * 3; | // 3! |
return 1 * 2 * 3 * 4; | // 4! |
In the solution, we reverse the array elements by using a recursive function literal. Instead of beginning at index zero, we begin the array from the end length, and decrement this value with each iteration. When the value is zero, we return the string.
If we want the reverse, to concatenate the array elements, in order, to a string, we modify the function:
var orderArray = function(x,indx,str) { return indx == x.length-1 ? str : orderArray(x,++indx,(str+=x[indx] + " ")); } var arr = new Array('apple','orange','peach','lime'); var str = orderArray(arr,-1,"");
Rather than the length of the array, we start with an index value of –1, and continue the loop until one less than the length of the array. We increment the index value, rather than decrement with each loop.
Most recursive functions can be replaced with code that performs the same function linearly, via some kind of loop. The advantage of recursion is that recursive functions can be fast, and efficient. The downside, though, is that recursive functions can be very memory-intensive.
See Also
Some of the negative consequences of recursive functions can be mitigated via memoization, covered in Recipe 6.9. Accessing the outer variable internally with the recursive function is covered in Recipe 6.7, which goes into function scope.
6.7. Create a Function That Remembers Its State
Problem
You want to create a function that can remember static data, but without having to use global variables and without resending the same data with each function call.
Solution
Create an outer function that takes one or more parameters, and then an inner function that also takes one or more parameters but uses both its and its parent function’s parameters in order to perform its functionality. Return the inner function from the outer function, and assign it to a variable. From that point, use the variable as a function:
function greetingMaker(greeting) { function addName(name) { return greeting + " " + name; } return addName; } // Now, create new partial functions var daytimeGreeting = greetingMaker("Good Day to you"); var nightGreeting = greetingMaker("Good Evening"); ... // if daytime alert(daytimeGreeting(name)); // if night alert(nightGreeting(name));
Discussion
We want to avoid global variables as much as possible because of potential clashes between libraries. However, there are times when you need to store data to be used across several function calls, and you don’t want to have to repeatedly send this information to the function each time.
A way to persist this data from one function to another other is to create one of the functions within the other, so both have access to the data, and then return the inner function from the outer. Returning one function from another is known as a function closure. Before I get into the specifics of function closure, I want to spend a few minutes on functions and scope.
Note
This type of function closure is also known as a partial function, or currying, which is covered in detail in Recipe 6.8.
In the solution, the inner function
addName
is defined in the outer function
greetingMaker
. Both of the functions have one
argument. The inner function has access to both its argument and the
outer function’s argument, but the outer function cannot access the
argument passed to the inner function. The inner function can operate on
the outer function’s parameters because it is operating within the same
context, or scope, of the outer function.
In JavaScript, there is one scope that is created for the outermost application environment. All global variables, functions, and objects are contained within this outer scope.
When you create a function, you create a new scope that exists as long as the function exists. The function has access to all variables in its scope, as well as all of the variables from the outer scope, but the outer scope does not have access to the variables in the function. Because of these scoping rules, we can access window and document objects in all of our browser applications, and the inner function in the solution can also access the data passed to, or originating in, the outer function that wraps it.
Note
This also explains how the recursive functions in Recipe 6.6 can internally access the variables they’re assigned to in the outer application scope.
However, the outer function cannot access the inner function’s arguments or local data, because they exist in a different scope.
An inner function doesn’t have to be returned from the outer function. It could be an invoked direction in the code in the outer function. When it is returned, like in the solution, and the following code:
function outer (x) { return function(y) { return x * y; }; } var multiThree = outer(3); alert(multiThree(2)); // 6 is printed alert(multiThree(3)); // 9 is printed
the returned function forms a closure. A JavaScript closure is a variable local to a function that remains alive when the function returns.
When the inner function is returned from the outer function, its application scope at the time, including all references to the outer function’s variables, is now passed to the outer, global scope. So even though the outer function’s application scope no longer exists, the inner function’s scope exists at the time the function was returned, including a snapshot of the outer function’s data. It will continue to exist until the application is finished, and the outer, global scope is released.
So what happens to these variables when an application scope is released? JavaScript supports automatic garbage collection. What this means is you and I don’t have to manually allocate or deallocate memory for our variables. Instead, the memory for variables is created automatically when we create variables and objects, and deallocated automatically when the variable scope is released.
In the solution, the outer function greetingMaker
takes one argument, which is a
specific greeting. It also returns an inner function, addName
, which itself takes the person’s name.
In the code, greetingMaker
is called
twice, once with a daytime greeting, assigned to a variable called
daytimeGreeting
, and once with a
nighttime greeting, assigned to a variable called nightGreeting
.
Now, whenever we want to greet someone in daytime, we can use the
daytime greeting function, daytimeGreeting
, passing in the name of the
person. The same applies to the nighttime greeting function, nightGreeting
. No matter how many times each
is used, the greeting string doesn’t need to be respecified: we just
pass in a different name. The specialized variations of the greeting
remain in scope until the page that contains the application is unloaded
from the browser.
Closures are interesting and useful, especially when working with JavaScript objects, as we’ll see later in the book. But there is a downside to closures that turns up when we create accidental closures.
An accidental closure occurs when we code JavaScript that creates closures, but aren’t aware that we’ve done so. Each closure takes up memory, and the more closures we create, the more memory is used. The problem is compounded if the memory isn’t released when the application scope is released. When this happens, the result is a persistent memory leak.
Here’s an example of an accidental closure:
function outerFunction() { var doc = document.getElementById("doc"); var newObj = { 'doc' : doc}; doc.newObj = newObj; }
The newObj
contains one
property, doc
, which contains a
reference to the page element identified by doc
. But
then, this element is given a new property, newObj
, which contains a reference to the new
object you just created, which in turn contains a reference to the page
element. This is a circular reference from object to page element, and
page element to object.
The problem with this circular reference is exacerbated in earlier
versions of IE, because IE does not release memory associated with DOM
objects (such as the doc
element) if
application scope is released. Even leaving the page does not reclaim
the memory: you have to close the browser.
Note
Other browsers detected this type of situation and performed a cleanup when the user left the application (the web page where the JavaScript resided).
Luckily, newer versions of IE don’t have this problem. However, function closures should be deliberate, rather than accidental.
See Also
More on function closures and private function methods in Chapter 16. An excellent overview of function scope and closure is “JavaScript Closures”, by Richard Cornford. Though written in 2004, it’s still one of the best descriptions of closures. Mozilla provides a nice, clean description of closures at https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Working_with_Closures.
Recipe 6.8 also makes use of specialized function closure, specifically for simplifying the number of arguments that have to be passed to functions, an effect called currying.
6.8. Improving Application Performance with a Generalized Currying Function
Problem
You have several functions you want to simplify by attaching recurring argument values to the functions, so the arguments don’t have to be repeated.
Solution
Use the concept of currying, a specialized
form of function closure, to create a function generator that takes the
function name and the persisted arguments, and returns a new partial
function that only needs the remaining arguments. Here is the curry
function I adapted from a function
created by Dustin Diaz, which works in all of this book’s target
browsers:
function curry (fn, scope) { var scope = scope || window; var args = []; for (var i=2, len = arguments.length; i < len; ++i) { args.push(arguments[i]); }; return function() { var args2 = []; for (var i = 0; i < arguments.length; i++) { args2.push(arguments[i]); } var argstotal = args.concat(args2); return fn.apply(scope, argstotal); }; }
When you want to curry a function, you pass the function name, and whatever values you want statically assigned to the returned function:
function diffPoint (x1, y1, x2, y2) { return [Math.abs(x2 - x1), Math.abs(y2 - y1)]; } var diffOrigin = curry(diffPoint, null, 3.0, 4.0); var newPt = diffOrigin(6.42, 8.0); // array with 3.42, 4
Discussion
A typical function could be like the following, which takes two pairs of numbers (an origin and a new location) and returns an array with the difference between the two:
function diffPoint (x1, y1, x2, y2) { return [x2 - x1, y2 - y1]; }
The function is fine, but if the origin is going to be the same across many calls to the function, wouldn’t it be nice to somehow attach this information to the function? Currying is the process that allows us to do this.
Currying is a way of statically attaching more than one argument to a function, so the argument doesn’t have to be duplicated. We demonstrated one form of currying in Recipe 6.7, but in that case, we created a single purpose outer function in order to provide the currying functionality for the inner function.
In the solution, what I’ve done is create a multipurpose currying
function that can perform this functionality for any method in which we
want to split parameters between those repeated and those not. In the
curry
method, I capture the arguments
for the first function call, and those from the second, concatenate the
two, and then use the Function apply
method to return a
function with the combined set of arguments.
The code then uses the curry
method to create a new function, diffOrigin
, that finds the difference between
the point and a given origin, in this case, where origin is at x = 3, y = 4:
var diffOrigin = curry(diffPoint, null, 3.0, 4.0); var newPt = diffOrigin(6.42, 8.0); // array with 3.42, 4
We can use the same curry method with diffPoint
and another set of origin
points:
var farPoint = curry (diffPoint, null, 183.66, 98.77);
and then use it as many times as needed:
var ptA = farPoint(1.33, 2.11); var point0 = genFunction(0,0); // 182.329999..., 96.66
The curry method can also take a scope as an argument. In the example, there is no specialized scope, so the window object is used. However, I could also have passed in a reference to an element or other object, and then the inner function would have access to that object’s context.
See Also
A curry
method is provided in
many JavaScript libraries, such as Dojo, jQuery, and Prototype.js,
either directly or as an extension. The Function apply
method is demonstrated in Chapter 16, beginning with Recipe 16.5. See another
example of function closure and currying in Recipe 6.7.
6.9. Improve Application Performance with Memoization (Caching Calculations)
Problem
You want to optimize your JavaScript applications and libraries by reducing the need to repeat complex and CPU-intensive computations.
Solution
Use function memoization in order to cache the results of a complex calculation. Here, I’m borrowing an example from Douglas Crockford’s book, JavaScript: The Good Parts (O’Reilly), as applied to the code to generate a Fibonacci number:
var fibonacci = function () { var memo = [0,1]; var fib = function (n) { var result = memo[n]; if (typeof result != "number") { result = fib(n -1) + fib(n - 2); memo[n] = result; } return result; }; return fib; }();
Discussion
Memoization is the process where interim values are cached, rather than recreated, cutting down on the number of iterations and computation time. It works especially well with something like the Fibonacci numbers, or factorials, both of which operate against previously calculated values. For instance, we can look at a factorial, 4!, as follows:
return 1; | // 0! |
return 1; | // 1! |
return 1 * 2; | // 2! |
return 1 * 2 * 3; | // 3! |
return 1 * 2 * 3 * 4; | // 4! |
But we can also view it as: | 3! * 4 // 4! |
In other words, if we cache the value for 2! when creating 3!, we don’t need to recalculate 1 * 2; and if we cache 3! when calculating 4!, we don’t need 1 * 2 * 3, and so on.
Memoization is built into some languages, such as Java, Perl, Lisp, and others, but not into JavaScript. If we want to memoize a function, we have to build the functionality ourselves. The key to the effective use of memoization is being aware that the technique doesn’t result in performance improvements until the number of operations is significant enough to compensate for the extra effort.
Example 6-3 shows the memoized and nonmemoized versions of the Fibonacci function that Crockford provided in his book. The example also uses the Console API to record times, so you’ll need to run the application in Firefox or Safari. Make sure the tool’s Console is open. Note that the calculations are intense and can take a considerable time. Save any work you have in other tabs. You may have to override a message given by the browser, too, about killing a script that’s running a long time.
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Testing Memoization</title> <script> //<![CDATA[ window.onload=function() { // Memoized Function var fibonacci = function () { var memo = [0,1]; var fib = function (n) { var result = memo[n]; if (typeof result != "number") { result = fib(n -1) + fib(n - 2); memo[n] = result; } return result; }; return fib; }(); // nonmemoized function var fib = function (n) { return n < 2 ? n : fib(n - 1) + fib(n - 2); }; // run nonmemo function, with timer console.time("non-memo"); for (var i = 0; i <= 10; i++) { console.log(i + " " + fib(i)); } console.timeEnd("non-memo"); // now, memo function with timer console.time("memo"); for (var i = 0; i <= 10; i++) { console.log(i + " " + fibonacci(i)); } console.timeEnd("memo"); } //--><!]]> </script> </head> <body> <p>content</p> </body> </html>
First, the code is run against a number of 10. The result is as follows, and as shown in Figure 6-2:
non-memo: 39ms memo: 38ms
The result generates one big “meh.” In the second run, though, the
code is edited to run the code in a for
loop of 30. The result is as
follows:
non-memo: 54761ms memo: 160ms
A major change.
See Also
There’s little information on JavaScript memoization online. There has been effort to create memoize functions that can work with all functions that would benefit. Crockford provided one in his book, JavaScript: The Good Parts (O’Reilly). Other discussions on the topic can be found by searching for “JavaScript memoization” in your favorite search engine.
6.10. Using an Anonymous Function to Wrap Global Variables
Problem
You need to create a variable that maintains state between function calls, but you want to avoid global variables.
Solution
Use an anonymous function to wrap variables and functions both:
<!DOCTYPE html> <head> <title>faux Global</title> <script> (function() { var i = 0; function increment() { i++; alert("value is " + i); } function runIncrement() { while (i < 5) { increment(); } } window.onload=function() { runIncrement(); } })(); </script> </head> <body> </body>
Discussion
The functionality demonstrated in the solution has existed for some time, but I’ve only seen anonymous functions as a way to scope what would normally be global variables in John Resig’s work with the jQuery framework library. It’s used as a way of wrapping jQuery plug-in functions so that the code can use the jQuery dollar sign function ($) when the jQuery plug-in is used with another framework library, such as Prototype, which also uses the dollar sign function:
// swap colors, blue and red (function($) { $.fn.flashBlueRed = function() { return this.each(function() { var hex = $.bbConvertRGBtoHex($(this).css("background-color")); if (hex == "#0000ff") { $(this).css("background-color", "#ff0000"); } else { $(this).css("background-color", "#0000ff"); } }); }; })(jQuery);
The approach consists of surrounding the code block with parentheses, beginning with the anonymous function syntax, and following up with the code block and then the final function closure. It could be the following, if there’s no parameter passed into the code block:
})();
or the following, if you are passing a parameter into the function:
})(jQuery);
Now you can use as many “global” variables as you need without polluting the global space or colliding with global variables used in other libraries.
See Also
Recipe 17.7 covers writing jQuery plug-ins.
Get JavaScript Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.