Posts Tagged ‘javascript’

Ways of passing data to functions in JavaScript

Friday, December 4th, 2009

Passing data is quite important in functional programming languages like JavaScript. When there are multiple functions (which is most of the time), there needs to be a way to pass data between the functions. This is done by passing values in parenthesis: myFunction(myData). Even when there is no data to be passed, we still have to declare and execute functions by using parenthesis: myFunction().

Simple Passing

I’ve already referred to the common method of passing data. Here’s an example of the code in action:

function greeting (name) {
    alert('Hello ' + name);
}
var personsName = 'Joe';
greeting(personsName);  // Hello Joe

This example only passes one variable to the function. Note that we can get rid of the variable personsName and make the string on the fly. So the code above is equivalent to this:

function greeting (name) {
    alert('Hello ' + name);
}
greeting('Joe');  // Hello Joe

Ok. Now let’s suppose we have a function that accepts two variables:

function greeting (firstName, lastName) {
    alert('Hello ' + firstName + ' ' + lastName);
}
greeting('Joe', 'Schmoe');  // Hello Joe Schmoe

This doesn’t look too hard. But there’s a catch – the person writing the code has to remember the order of variables to pass in. Suppose they call the function like this:

function greeting (firstName, lastName) {
    alert('Hello ' + firstName + ' ' + lastName);
}
greeting('Schmoe', 'Joe');  // Hello Schmoe Joe

That’s no good! This isn’t the result we want. In the case of firstName and lastName the variable order isn’t too hard to remember, but in other cases the variables aren’t in any logical order, which can cause confusion.

No constructor overloading

Unlike other languages such as C++ and Java, JavaScript has no constructor overloading. In fact, JavaScript is (for better or worse) not even strict about enforcing the number of variables passed in. For example, the following code works fine and throws no errors, even though we’re not passing in a variable in the function call:

function test (someVar) {
    // do stuff
};
test();  // no errors!

It’s only when you try to use someVar within the function that causes the problems. Otherwise, everything’s working just fine and dandy.

What happens if we try the other case scenario: pass in more variables than the function expects? No errors again:

function test () {
    // do stuff
};
test('testing 123');  // again, no errors

And what happens if we try to declare a function with the same name? No errors, but the previous function is overwritten (this is generally to be avoided of course):

function test () {
    alert('First function');
};
function test () {
    alert('Second function');
};
test();  // Second function

Because JavaScript has no function overloading, all it takes to overwrite another function is to redeclare a function with the same name. It doesn’t matter what sort of arguments they accept.

Passing with the help of the arguments object

As it turns out, JavaScript has a handy arguments object to access the arguments passed into each function:

function test () {
    alert(arguments[0]);    // testing 123
};
test('testing 123');

In the above case the arguments object acts just as an array – it’s 0-indexed and can be used to access any arbitrary number of arguments. But arguments also has an interesting and useful property: length. Using arguments.length, we can traverse the array of arguments. This is handy in cases where we might want to add an arbitrary number of elements together:

function add () {
    var sumTotal = 0;                        // initialize total to 0

    for(var i=0; i<arguments.length; i++) {  // for each argument
        sumTotal += arguments[i];            // add current argument to total
    }

    alert(sumTotal);
};
add(2, 3, 4);  // 9
add(1, 1, 1, 1, 1, 1, 1, 1, 1);  // 9

Passing an object

JavaScript libraries such as YUI have already learned that the variable order is a common nuisance and an opportunity to introduce errors, so they’ve come up with a solution: pass a single object to the function. It ends up looking something like this:

function greeting (obj) {
    alert('Hello ' + obj.first + ' ' + obj.last);
}
var nameObject = {};
nameObject.first = 'Joe';
nameObject.last = 'Schmoe';
greeting(nameObject);  // Hello Joe Schmoe

Now the variables become properties of a single object which is passed into the function. And it doesn’t matter which order the properties are declared in, which is a great relief to the developer.

Note that we can simplify the above code:

function greeting (obj) {
    alert('Hello ' + obj.first + ' ' + obj.last);
}
var nameObject = {
    first: 'Joe',
    last: 'Schmoe'
};
greeting(nameObject);  // Hello Joe Schmoe

And we can simplify even further:

function greeting (obj) {
    alert('Hello ' + obj.first + ' ' + obj.last);
}
greeting({
    first: 'Joe',
    last: 'Schmoe'
});  // Hello Joe Schmoe

This is the form commonly used in these JavaScript libraries. It’s easy to copy-and-paste example code, but it might not always be so obvious what’s going on behind the scenes. You can see that just as we bypassed declaring a named variable in the Simple Passing model (with greeting(”)), here we use the same shortcut and bypass declaring a named object (with greeting({})).

call() and apply()

These two methods have different techniques for passing data to functions, but I’m going to have to hold off on them for now. It’s a bit complicated, since they’re only used to execute methods (functions) in other object contexts. But seeing as I need to explain object context to get into that, I’ll save that for a future entry!

Pitfalls of declaring variables in JavaScript

Wednesday, November 18th, 2009

Introduction

One of the things that’s always been confusing to me is that there are multiple ways to declare variables in JavaScript, and some ways are better than others. For the beginner programmer, just getting to code to work means complete success, but for the intermediate or advanced programmer, this is just the first step. The next step is to clean up the code and make sure everything is written in the best way it could have been written.

Declaring variables seems like such a basic thing that one almost feels insulted reading about it. Yes, this whole post is about declaring variables. But not just this – it’s about declaring variables the right way. This means declaring variables in the scope they were intended to be declared in.  For the most part this means writing variables in the scope of a function, as opposed to the global namespace (in which everything becomes a property of the window object).

Global variables can be declared in functions

When I was starting to learn JavaScript, I read about global and functional scope and wrongly assumed that functions completely protected the variables declared inside.  As it turns out, there’s many ways to create global variables in JavaScript, and none of them throw up red flags or sound off bells and whistles (unfortunately).

Here’s a few ways to create global variables in JavaScript:

// Creating global variables outside of a function
window.global1 = 1;
global2 = 2;
var global3 = 3;

// Created global variables within a function
function test() {
    global4 = 4;
    window.global5 = 5;
};
test();

You can confirm this for yourself by checking the values of the variables with alert().

Good practice: always precede variables with var

What I learned was that it was essentially good practice to always write variables preceded by the var keyword.  For variables declared outside of functions this has no effect – they are still global, but for variables within functions this ensures that they’re kept within their functional scope:

var global = null;
function test() {
    var local = null;
}
test();

Same name, but different variables

And check this out – confusingly, you can create a global variable, then create a variable with the same name that’s functionally-scoped, yet a completely different variable!

var number = 0;

function test() {
    var number = 1;
}
test();

alert(number);  // 0

When you precede a variable with the var keyword, you’re essentially saying you’re creating the variable for the first time.  So when you create “number” inside the function, no error is thrown because the variable is created in the function’s scope.  If you try to create another variable with the name “number” inside the function, you will get an error because it’s already been defined within the scope.

There’s no such thing as magical protective parenthesis

For some reason I was further mistaken into believing that extra parenthesis around an anonymous function magically protected all the variables within:

(function() {
    global = null;
    var local = null;
})();

Nope – as you can see, the global variable is still global since it’s not preceded by the var keyword.  However, the local variable is local because it’s within its functional scope and preceded by the var keyword.

Shorthand for declaring multiple functionally-scoped variables

The following code ensures each variable is functionally (locally) scoped, even though only the first variable is preceded by the var keyword:

// shorthand #1
function test() {
    var local1 = null,
        local2 = null;
}
test();

// shorthand #2
function test2() {
    var local1, local2;  // these are of type 'undefined' but they have functional scope!
}
test2();

Multiple variable declaration equivalence gives different scope to each variable

Today I learned another way to mistakenly create a global variable.  Trying to be fancy and declare multiple variables to be the same value, I mistakenly created a global variable (again, no bells and whistles went off to warn me, unfortunately):

function test() {
    var local = global = null;
}
test();

This sets both variables to “null” using the shortest code possible, but unfortunately only the variable “local” is preceded by the var keyword, so only that variable will be in its proper functional scope. Variable “global”, on the other hand, is… well… global. (thanks to Crescent Fish)

You learn something new every day…

Update 1

If you want to check your code for “accidental global variables” you can use JSLint or you can even use Firebug (click on the Script tab, then click on “New watch expression…”, then type “window”, which will display all the properties of the window object – these are all global variables!). Thanks to Nick for the Firebug tip.

Update 2

Just another quick note to remind you that after a variable has been initially declared, the scope will not change. Which is why you can redefine variables, but have them keep their scope:

function test() {
    var local = null;
    local = 5;    // still keeps its local/functional scope
}
test();

As you can see above, the variable “local” keeps its local scope, even though it’s redefined to be 5. This is one of the reasons it’s recommended to declare all variables at the start of a function – to make sure the scope gets set correctly.

One final note: var should only be used when declaring a variable for the first time. If you try to use var for the same variable name in the same scope, it will result in an error:

function test() {
    var local = null;
    var local = 5;    // throws an error!
}
test();

Update 3: Graphical representation

Scope in JavaScript

Scope in JavaScript

JavaScript Tidbit: Block scope with “let”

Tuesday, September 15th, 2009

JavaScript has functional scope. Meaning that if you (properly) define variables within functions, those variables remain accessible only inside the function.

Block scope, on the other hand, defines scope within a block of code, usually defined by braces. JavaScript now has block scope as of version 1.7, which means it’s available in these browsers:

  • Firefox 2+

Block scope is enabled in JavaScript with the use of “let”:

let(x=100) {
    alert(x);
};

It also works perfectly well on one line, without the use of braces:

let(x=100) alert(x);

Note that we can define global variables with the same name outside the block scope and the variables won’t interfere with each other:

x = 200;
let(x=100) alert(x);
alert(x);
// result: 100, 200

Note that there’s a slight caveat – not only is this not available in any version of IE, but it also requires a special script type declaration in order to work (at least for Firefox): type=”text/javascript;version=1.7″

References:
JavaScript Versions
Video: Best Practices in Javascript Library Design (John Resig)
New in JavaScript 1.7

JavaScript Tidbit: Shorthand Object Instantiation

Monday, September 14th, 2009

The skinny: here’s a neat little trick to reduce the amount of code users have to type to instantiate objects:

function jQuery(str, con){
    if ( window == this )
        return new jQuery(str, con);
    // ...
}

new jQuery("#foo"); // this is now equivalent...
jQuery("#foo");     // ...to this!

Explanation: when jQuery(“#foo”) is typed, the function first determines if the context in which it’s being called is the global object (window).  If it is, it returns an instantiation of itself.  When it’s instantiated, the context in which it’s being called is inside its own function, and NOT within the global object (window), thus it bypasses our little instantiation trick and moves on to execute any remaining code in the function.

From John Resig’s Best Practices in Javascript Library Design