WEBSITE

JavaScript Patterns : Conventions

9/23/2010 11:45:18 AM

1. Number Conversions with parseInt()

Using parseInt() you can get a numeric value from a string. The function accepts a second radix parameter, which is often omitted but shouldn’t be. The problems occur when the string to parse starts with 0: for example, a part of a date entered into a form field. Strings that start with 0 are treated as octal numbers (base 8) in ECMAScript 3; however, this has changed in ES5. To avoid inconsistency and unexpected results, always specify the radix parameter:

var month = "06",
year = "09";
month = parseInt(month, 10);
year = parseInt(year, 10);

In this example, if you omit the radix parameter like parseInt(year), the returned value will be 0, because “09” assumes octal number (as if you did parseInt(year, 8)) and 09 is not a valid digit in base 8.

Alternative ways to convert a string to a number include:

+"08" // result is 8
Number("08") // 8

These are often faster than parseInt(), because parseInt(), as the name suggests, parses and doesn’t simply convert. But if you’re expecting input such as “08 hello”, parseInt() will return a number, whereas the others will fail with NaN.

2. Coding Conventions

It’s important to establish and follow coding conventions—they make your code consistent, predictable, and much easier to read and understand. A new developer joining the team can read through the conventions and be productive much sooner, understanding the code written by any other team member.

Many flamewars have been fought in meetings and on mailing lists over specific aspects of certain coding conventions (for example, the code indentation—tabs or spaces?). So if you’re the one suggesting the adoption of conventions in your organization, be prepared to face resistance and hear different but equally strong opinions. Remember that it’s much more important to establish and consistently follow a convention, any convention, than what the exact details of that convention will be.

2.1. Indentation

Code without indentation is impossible to read. The only thing worse is code with inconsistent indentation, because it looks like it’s following a convention, but it may have confusing surprises along the way. It’s important to standardize the use of indentation.

Some developers prefer indentation with tabs, because anyone can tweak their editor to display the tabs with the individually preferred number of spaces. Some prefer spaces—usually four. It doesn’t matter as long as everyone in the team follows the same convention. This book, for example, uses four-space indentation, which is also the default in JSLint.

And what should you indent? The rule is simple—anything within curly braces. This means the bodies of functions, loops (do, while, for, for-in), ifs, switches, and object properties in the object literal notation. The following code shows some examples of using indentation:

function outer(a, b) {
var c = 1,
d = 2,
inner;
if (a > b) {
inner = function () {
return {
r: c - d
};
};
} else {
inner = function () {
return {
r: c + d
};
};
}
return inner;
}

2.2. Curly Braces

Curly braces should always be used, even in cases when they are optional. Technically, if you have only one statement in an if or a for, curly braces are not required, but you should always use them anyway. It makes the code more consistent and easier to update.

Imagine you have a for loop with one statement only. You could omit the braces and there will be no syntax error:

// bad practice
for (var i = 0; i < 10; i += 1)
alert(i);

But what if, later on, you add another line in the body of the loop?

// bad practice
for (var i = 0; i < 10; i += 1)
alert(i);
alert(i + " is " + (i % 2 ? "odd" : "even"));

The second alert is outside the loop although the indentation may trick you. The best thing to do in the long run is to always use the braces, even for one-line blocks:

// better
for (var i = 0; i < 10; i += 1) {
alert(i);
}

Similarly for if conditions:

// bad
if (true)
alert(1);
else
alert(2);

// better
if (true) {
alert(1);
} else {
alert(2);
}

2.3. Opening Brace Location

Developers also tend to have preferences about where the opening curly brace should be—on the same line or on the following line?

if (true) {
alert("It's TRUE!");
}

Or:

if (true)
{
alert("It's TRUE!");
}

In this specific example, it’s a matter of preference, but there are cases in which the program might behave differently depending on where the brace is. This is because of the semicolon insertion mechanism—JavaScript is not picky when you choose not to end your lines properly with a semicolon and adds it for you. This behavior can cause troubles when a function returns an object literal and the opening brace is on the next line:

// warning: unexpected return value
function func() {
return
{
name: "Batman"
};
}

If you expect this function to return an object with a name property, you’ll be surprised. Because of the implied semicolons, the function returns undefined. The preceding code is equivalent to this one:

// warning: unexpected return value
function func() {
return undefined;
// unreachable code follows...
{
name: "Batman"
};
}

In conclusion, always use curly braces and always put the opening one on the same line as the previous statement:

function func() {
return {
name: "Batman"
};
}


Note: A note on semicolons: Just like with the curly braces, you should always use semicolons, even when they are implied by the JavaScript parsers. This not only promotes discipline and a more rigorous approach to the code but also helps resolve ambiguities, as the previous example showed.

2.4. White Space

The use of white space can also contribute to improved readability and consistency of the code. In written English sentences you use intervals after commas and periods. In JavaScript you follow the same logic and add intervals after list-like expressions (equivalent to commas) and end-of-statements (equivalent to completing a “thought”).

Good places to use a white space include:

  • After the semicolons that separate the parts of a for loop: for example, for (var i = 0; i < 10; i += 1) {...}

  • Initializing multiple variables (i and max) in a for loop: for (var i = 0, max = 10; i < max; i += 1) {...}

  • After the commas that delimit array items: var a = [1, 2, 3];

  • After commas in object properties and after colons that divide property names and their values: var o = {a: 1, b: 2};

  • Delimiting function arguments: myFunc(a, b, c)

  • Before the curly braces in function declarations: function myFunc() {}

  • After function in anonymous function expressions: var myFunc = function () {};

Another good use for white space is to separate all operators and their operands with spaces, which basically means use a space before and after +, -, *, =, <, >, <=, >=, ===, !==, &&, ||, +=, and so on:

// generous and consistent spacing
// makes the code easier to read
// allowing it to "breathe"
var d = 0,
a = b + 1;
if (a && b && c) {
d = a % c;
a += d;
}

// antipattern
// missing or inconsistent spaces
// make the code confusing
var d= 0,
a =b+1;
if (a&& b&&c) {
d=a %c;
a+= d;
}

And a final note about white space—curly braces spacing. It’s good to use a space:

  • Before opening curly braces ({) in functions, if-else cases, loops, and object literals

  • Between the closing curly brace (}) and else or while

A case against liberal use of white space might be that it could increase the file size, but minification (discussed later in the chapter) takes care of this issue.


Note: An often-overlooked aspect of code readability is the use of vertical white space. You can use blank lines to separate units of code, just as paragraphs are used in literature to separate ideas.

3. Naming Conventions

Another way to make your code more predictable and maintainable is to adopt naming conventions. That means choosing names for your variables and functions in a consistent manner.

Below are some naming convention suggestions that you can adopt as-is or tweak to your liking. Again, having a convention and following it consistently is much more important than what that convention actually is.

3.1. Capitalizing Constructors

JavaScript doesn’t have classes but has constructor functions invoked with new:

var adam = new Person();

Because constructors are still just functions, it helps if you can tell, just by looking at a function name, whether it was supposed to behave as a constructor or as a normal function.

Naming constructors with a capital first letter provides that hint. Using lowercase for functions and methods indicates that they are not supposed to be called with new:

function MyConstructor() {...}
function myFunction() {...}

In the next chapter there are some patterns that enable you to programmatically force your constructors to behave like constructors, but simply following the naming convention is helpful in itself, at least for programmers reading the source code.

3.2. Separating Words

When you have multiple words in a variable or a function name, it’s a good idea to follow a convention as to how the words will be separated. A common convention is to use the so-called camel case. Following the camel case convention, you type the words in lowercase, only capitalizing the first letter in each word.

For your constructors, you can use upper camel case, as in MyConstructor(), and for function and method names, you can use lower camel case, as in myFunction(), calculateArea() and getFirstName().

And what about variables that are not functions? Developers commonly use lower camel case for variable names, but another good idea is to use all lowercase words delimited by an underscore: for example, first_name, favorite_bands, and old_company_name. This notation helps you visually distinguish between functions and all other identifiers—primitives and objects.

ECMAScript uses camel case for both methods and properties, although the multiword property names are rare (lastIndex and ignoreCase properties of regular expression objects).

3.3. Other Naming Patterns

Sometimes developers use a naming convention to make up or substitute language features.

For example, there is no way to define constants in JavaScript (although there are some built-in such as Number.MAX_VALUE), so developers have adopted the convention of using all-caps for naming variables that shouldn’t change values during the life of the program, like:

// precious constants, please don't touch
var PI = 3.14,
MAX_WIDTH = 800;

There’s another convention that competes for the use of all caps: using capital letters for names of global variables. Naming globals with all caps can reinforce the practice of minimizing their number and can make them easily distinguishable.

Another case of using a convention to mimic functionality is the private members convention. Although you can implement true privacy in JavaScript, sometimes developers find it easier to just use an underscore prefix to denote a private method or property. Consider the following example:

var person = {
getName: function () {
return this._getFirst() + ' ' + this._getLast();
},
_getFirst: function () {
// ...
},
_getLast: function () {
// ...
}
};

In this example getName() is meant to be a public method, part of the stable API, whereas _getFirst() and _getLast() are meant to be private. They are still normal public methods, but using the underscore prefix warns the users of the person object that these methods are not guaranteed to work in the next release and shouldn’t be used directly. Note that JSLint will complain about the underscore prefixes, unless you set the option nomen: false.

Following are some varieties to the _private convention:

  • Using a trailing underscore to mean private, as in name_ and getElements_()

  • Using one underscore prefix for _protected properties and two for __private properties

  • In Firefox some internal properties not technically part of the language are available, and they are named with a two underscores prefix and a two underscore suffix, such as __proto__ and __parent__


Other  
 
Most View
The HP Virtual Server Environment : Example nPartition Management Scenario (part 4) - Rebooting and Booting nPartitions
HyperJuice 2 - Hungry For Power
Android 4.0 Ice Cream Sandwich Guided Tour (Part 1)
IP Cameras Keep Watch (Part 2) - Trendnet TV-IP572WI, Axis M5014, Trendnet TV-IP322P
Programming .NET Components : Serialization Events (part 1) - Applying the Event Attributes
Sigma 120-300mm F/2.8 DG OS HSM S Lens Review
Tips To Speed Up Your Device (Part 2)
SQL Server 2012 : Local Transaction Support in SQL Server (part 1) - Explicit Transaction Mode
Anti-Virus Software - The Best Security Software To Protect Your PC (Part 3)
The HP Virtual Server Environment : nPartition Management Paradigms (part 2) - Remote Management via an nPartition Paradigm, Remote Management via the MP Paradigm
Top 10
Sharepoint 2013 : Farm Management - Disable a Timer Job,Start a Timer Job, Set the Schedule for a Timer Job
Sharepoint 2013 : Farm Management - Display Available Timer Jobs on the Farm, Get a Specific Timer Job, Enable a Timer Job
Sharepoint 2013 : Farm Management - Review Workflow Configuration Settings,Modify Workflow Configuration Settings
Sharepoint 2013 : Farm Management - Review SharePoint Designer Settings, Configure SharePoint Designer Settings
Sharepoint 2013 : Farm Management - Remove a Managed Path, Merge Log Files, End the Current Log File
SQL Server 2012 : Policy Based Management - Evaluating Policies
SQL Server 2012 : Defining Policies (part 3) - Creating Policies
SQL Server 2012 : Defining Policies (part 2) - Conditions
SQL Server 2012 : Defining Policies (part 1) - Management Facets
Microsoft Exchange Server 2010 : Configuring Anti-Spam and Message Filtering Options (part 4) - Preventing Internal Servers from Being Filtered