JavaScript and Infinity Basics
Don't Add Objects to the Global Namespace
Never declare a variable or function outside a function declaration because by doing so you make that variable or function available to all other JavaScript on that web page. Because we are building components that could be shown on web pages other than ones we own, such as a client's own website, we must make sure that we scope our JavaScript objects so they don't conflict with objects on the component's host page.
There are two ways to avoid adding objects to the global namespace:
-
Wrap your code in a self-invoking function.
-
Assign your object to a property on an already-global object.
Wrap Your Code in a Self-invoking Function
When a variable or function is defined inside another function, it is only visible inside that function. It is also visible to other functions inside that function, and functions inside that inner function and so on. In JavaScript, this is called a closure. When a variable or function is defined outside another function, the variable gets added to the web page's window object, which is the object that holds the page's global objects (or what I refer to as the "global namespace"). Properties that belong to the window object can be referenced with or without "window." in front of the object name.
To declare variables that do not pollute the global namespace but are still available to all the functions in a particular JS file, you need to create a closure by wrapping all of the code in your JS file inside a self-invoking function. A self-invoking function gets called immediately after its declaration and looks like this:
(function () {
// Your code goes here.
}());
If you look at the parts, it's just an anonymous function wrapped in parentheses with empty parentheses at the end to indicate that the code is a function call. All variables and functions you need in your JS file should go inside this function. Here's an example.
(function () {
var s = "hello";
function sayHello() {
alert(s); // This will show a message box that says "hello".
}
// Call the sayHello() function.
sayHello();
}());
// This will show a message box that says "undefined"
// because s is not defined outside the self-invoking
// function.
alert(s);
// This will cause an error because sayHello()
// is not defined outside the self-invoking function.
sayHello();
Assign Your Object to a Property on an Already-global Object
Sometimes you absolutely need to have variables or functions that are available to the entire page, such as when registering client script from an ASP.NET code-behind class. In these cases, you should scope your object to an object that is already globally defined. UI model forms several different JavaScript libraries for various tasks such as showing a combo box or a grid, all of which put one object in the global namespace. One of these libraries is our homegrown BBUI library that we have developed to wrap up the common tasks for UI model. I reserved a namespace in BBUI called "globals" under which you can put any page-level objects you need without fear of name collisions. Here's an example of registering a client script block on an ASP.NET page that assigns an object to the BBUI.globals namespace:
Dim databaseName = Request.QueryString("databaseName")
Dim databaseNameScript = "BBUI.globals.databaseName = '" & databaseName.Replace("'", "\'") & "';"
Page.ClientScript.RegisterStartupScript(Me.GetType(), "databaseName", databaseNameScript, True)
And here is an example of the JavaScript that might use the script registered on the page:
(function () {
function reportDatabaseName() {
alert("You are logged into the " + BBUI.globals.databaseName + " database.");
}
reportDatabaseName();
})();
It is very unlikely that you will ever hit this scenario when writing a form with UI model since you won't be dealing with ASP.NET; this is rather for other projects that may have its own web front-end and are taking advantage of the BBUI library.
Let's Review
-
Do not pollute the global namespace – write your code inside a self-invoking function.
-
Download and install Blackbaud.AppFx.HTMLLINT.exe within your instance of Visual Studio. See Setting up Visual Studio for JavaScript Development.
-
Use Blackbaud.AppFx.HTMLLINT.exe to "lint" your JS files and check your HTML files.