Wednesday, 3 December 2014

Javascript Best Practise

JavaScript utilizes two different kinds of equality operators: === | !== and == | != It is considered best practice to always use the former set when comparing.
"If two operands are of the same type and value, then === produces true and !== produces false." - JavaScript: The Good Parts
However, when working with == and !=, you'll run into issues when working with different types. In these cases, they'll try to coerce the values, unsuccessfully.

The == (or !=) operator performs an automatic type conversion if needed. The === (or !==) operator will not perform any conversion. It compares the value and the type, which could be considered faster than ==.
[10] === 10    // is false
[10]  == 10    // is true
'10' == 10     // is true
'10' === 10    // is false
 []   == 0     // is true
 [] ===  0     // is false
 '' == false   // is true but true == "a" is false
 '' ===   false // is false 

For those unfamiliar, the "eval" function gives us access to JavaScript's compiler. Essentially, we can execute a string's result by passing it as a parameter of "eval".
Not only will this decrease your script's performance substantially, but it also poses a huge security risk because it grants far too much power to the passed in text. Avoid it!
Technically, you can get away with omitting most curly braces and semi-colons. Most browsers will correctly interpret the following:
1
2
if(someVariableExists)
   x = false
However, consider this:
1
2
3
if(someVariableExists)
   x = false
   anotherFunctionCall();
One might think that the code above would be equivalent to:
1
2
3
4
if(someVariableExists) {
   x = false;
   anotherFunctionCall();
}
Unfortunately, he'd be wrong. In reality, it means:
1
2
3
4
if(someVariableExists) {
   x = false;
}
anotherFunctionCall();
As you'll notice, the indentation mimics the functionality of the curly brace. Needless to say, this is a terrible practice that should be avoided at all costs. The only time that curly braces should be omitted is with one-liners, and even this is a highly debated topic.
1
if(2 + 2 === 4) return 'nicely done';
What if, at a later date, you need to add more commands to this if statement. In order to do so, you would need to rewrite this block of code. Bottom line - tread with caution when omitting.
JSLint is a debugger written by Douglas Crockford. Simply paste in your script, and it'll quickly scan for any noticeable issues and errors in your code.
"JSLint takes a JavaScript source and scans it. If it finds a problem, it returns a message describing the problem and an approximate location within the source. The problem is not necessarily a syntax error, although it often is. JSLint looks at some style conventions as well as structural problems. It does not prove that your program is correct. It just provides another set of eyes to help spot problems."
- JSLint Documentation
Before signing off on a script, run it through JSLint just to be sure that you haven't made any mindless mistakes.
This tip has already been recommended in the previous article in this series. As it's highly appropriate though, I'll paste in the information.
Place JS at bottom
Remember -- the primary goal is to make the page load as quickly as possible for the user. When loading a script, the browser can't continue on until the entire file has been loaded. Thus, the user will have to wait longer before noticing any progress.
If you have JS files whose only purpose is to add functionality -- for example, after a button is clicked -- go ahead and place those files at the bottom, just before the closing body tag. This is absolutely a best practice.
1
2
3
4
5
<p>And now you know my favorite kinds of corn. </p>
<script type="text/javascript" src="path/to/file.js"></script>
<script type="text/javascript" src="path/to/anotherFile.js"></script>
</body>
</html>
When executing lengthy "for" statements, don't make the engine work any harder than it must. For example:
1
2
3
4
5
for(var i = 0; i < someArray.length; i++) {
   var container = document.getElementById('container');
   container.innerHtml += 'my number: ' + i;
   console.log(i);
}
Notice how we must determine the length of the array for each iteration, and how we traverse the dom to find the "container" element each time -- highly inefficient!
1
2
3
4
5
var container = document.getElementById('container');
for(var i = 0, len = someArray.length; i < len;  i++) {
   container.innerHtml += 'my number: ' + i;
   console.log(i);
}
Bonus points to the person who leaves a comment showing us how we can further improve the code block above.
Don't always reach for your handy-dandy "for" statement when you need to loop through an array or object. Be creative and find the quickest solution for the job at hand.
1
2
var arr = ['item 1', 'item 2', 'item 3', ...];
var list = '<ul><li>' + arr.join('</li><li>') + '</li></ul>';
I won’t bore you with benchmarks; you’ll just have to believe me (or test for yourself) - this is by far the fastest method!
Using native methods (like join()), regardless of what’s going on behind the abstraction layer, is usually much faster than any non-native alternative.
- James Padolsey, james.padolsey.com
"By reducing your global footprint to a single name, you significantly reduce the chance of bad interactions with other applications, widgets, or libraries."
- Douglas Crockford
1
2
3
4
5
6
var name = 'Jeffrey';
var lastName = 'Way';
function doSomething() {...}
console.log(name); // Jeffrey -- or window.name
1
2
3
4
5
6
var DudeNameSpace = {
   name : 'Jeffrey',
   lastName : 'Way',
   doSomething : function() {...}
}
console.log(DudeNameSpace.name); // Jeffrey
Notice how we've "reduced our footprint" to just the ridiculously named "DudeNameSpace" object.
It might seem unnecessary at first, but trust me, you WANT to comment your code as best as possible. What happens when you return to the project months later, only to find that you can't easily remember what your line of thinking was. Or, what if one of your colleagues needs to revise your code? Always, always comment important sections of your code.
1
2
3
4
// Cycle through array and echo out each name.
for(var i = 0, len = array.length; i < len; i++) {
   console.log(array[i]);
}
Always compensate for when JavaScript is disabled. It might be tempting to think, "The majority of my viewers have JavaScript enabled, so I won't worry about it." However, this would be a huge mistake.
Have you taken a moment to view your beautiful slider with JavaScript turned off? (Download the Web Developer Toolbar for an easy way to do so.) It might break your site completely. As a rule of thumb, design your site assuming that JavaScript will be disabled. Then, once you've done so, begin to progressively enhance your layout!
Consider the following code:
1
2
3
setInterval(
"document.getElementById('container').innerHTML += 'My new number: ' + i", 3000
);
Not only is this code inefficient, but it also functions in the same way as the "eval" function would. Never pass a string to SetInterval and SetTimeOut. Instead, pass a function name.
1
setInterval(someFunction, 3000);
At first glance, "With" statements seem like a smart idea. The basic concept is that they can be used to provide a shorthand for accessing deeply nested objects. For example...
1
2
3
4
with (being.person.man.bodyparts) {
   arms = true;
   legs = true;
}
-- instead of --
1
2
being.person.man.bodyparts.arms = true;
being.person.man.bodyparts.legs= true;
Unfortunately, after some testing, it was found that they "behave very badly when setting new members." Instead, you should use var.
1
2
3
var o = being.person.man.bodyparts;
o.arms = true;
o.legs = true;
There are multiple ways to create objects in JavaScript. Perhaps the more traditional method is to use the "new" constructor, like so:
1
2
3
4
5
6
var o = new Object();
o.name = 'Jeffrey';
o.lastName = 'Way';
o.someFunction = function() {
   console.log(this.name);
}
However, this method receives the "bad practice" stamp without actually being so. Instead, I recommend that you use the much more robust object literal method.
1
2
3
4
5
6
7
var o = {
   name: 'Jeffrey',
   lastName = 'Way',
   someFunction : function() {
      console.log(this.name);
   }
};
Note that if you simply want to create an empty object, {} will do the trick.
1
var o = {};
"Objects literals enable us to write code that supports lots of features yet still make it a relatively straightforward for the implementers of our code. No need to invoke constructors directly or maintain the correct order of arguments passed to functions, etc." - dyn-web.com
The same applies for creating a new array.
1
2
3
var a = new Array();
a[0] = "Joe";
a[1] = 'Plumber';
1
var a = ['Joe','Plumber'];
"A common error in JavaScript programs is to use an object when an array is required or an array when an object is required. The rule is simple: when the property names are small sequential integers, you should use an array. Otherwise, use an object." - Douglas Crockford
1
2
3
var someItem = 'some string';
var anotherItem = 'another string';
var oneMoreItem = 'one more string';
1
2
3
var someItem = 'some string',
    anotherItem = 'another string',
    oneMoreItem = 'one more string';
...Should be rather self-explanatory. I doubt there's any real speed improvements here, but it cleans up your code a bit.
Technically, most browsers will allow you to get away with omitting semi-colons.
1
2
3
4
var someItem = 'some string'
function doSomething() {
  return 'something'
}
Having said that, this is a very bad practice that can potentially lead to much bigger, and harder to find, issues.
1
2
3
4
var someItem = 'some string';
function doSomething() {
  return 'something';
}
When looping through items in an object, you might find that you'll also retrieve method functions as well. In order to work around this, always wrap your code in an if statement which filters the information
1
2
3
4
5
for(key in object) {
   if(object.hasOwnProperty(key) {
      ...then do something...
   }
}
As referenced from JavaScript: The Good Parts, by Douglas Crockford.
Need a quick and easy way to determine how long an operation takes? Use Firebug's "timer" feature to log the results.
1
2
3
4
5
function TimeTracker(){
 console.time("MyTimer");
 for(x=5000; x > 0; x--){}
 console.timeEnd("MyTimer");
}
While I'm a huge fan of web development blogs (like this one!), there really isn't a substitute for a book when grabbing some lunch, or just before you go to bed. Always keep a web development book on your bedside table. Here are some of my JavaScript favorites.
  • Object-Oriented JavaScript
  • JavaScript: The Good Parts
  • Learning jQuery 1.3
  • Learning JavaScript
Read them...multiple times. I still do!
Rather than calling a function, it's quite simple to make a function run automatically when a page loads, or a parent function is called. Simply wrap your function in parenthesis, and then append an additional set, which essentially calls the function.
1
2
3
4
5
6
(function doSomething() {
   return {
      name: 'jeff',
      lastName: 'way'
   };
})();
JavaScript libraries, such as jQuery and Mootools, can save you an enormous amount of time when coding -- especially with AJAX operations. Having said that, always keep in mind that a library can never be as fast as raw JavaScript (assuming you code correctly).
jQuery's "each" method is great for looping, but using a native "for" statement will always be an ounce quicker.
Although JavaScript 2 should have a built-in JSON parser, as of this writing, we still need to implement our own. Douglas Crockford, the creator of JSON, has already created a parser that you can use. It can be downloaded HERE.
Simply by importing the script, you'll gain access to a new JSON global object, which can then be used to parse your .json file.
1
2
3
4
5
6
var response = JSON.parse(xhr.responseText);
var container = document.getElementById('container');
for(var i = 0, len = response.length; i < len; i++) {
  container.innerHTML += '<li>' + response[i].name + ' : ' + response[i].email + '</li>';
}
Years ago, it wasn't uncommon to find the "language" attribute within script tags.
1
2
3
<script type="text/javascript" language="javascript">
...
</script>
However, this attribute has long since been deprecated; so leave it out.

25. Use Shortcut Notations

Shortcut notations keep your code snappy and easier to read once you get used to it.

This code
var lunch = new Array();
lunch[0]='Dosa';
lunch[1]='Roti';
lunch[2]='Rice';
lunch[3]='what the heck is this?';
 
Is the same as...
var lunch = [
   'Dosa',
   'Roti',
   'Rice',
   'what the heck is this?'
];
 
This code
if(v){
   var x = v;
} else {
   var x =10;
}
 
Is the same as...
var x = v || 10;
This code
var direction;
if(x > 100){
   direction = 1;
} else {
   direction = -1;
}
 
Is the same as...
var direction = (x > 100) ? 1 : -1;
 

26.Always Declare Local Variables

All variables used in a function should be declared as local variables.
Local variables must be declared with the var keyword, otherwise they will become global variables.
Note Strict mode does not allow undeclared variables.

27.Declarations on Top

It is good coding practice to put all declarations at the top of each script or function.
This gives better, cleaner code, and reduces the possibility of accidental re-declarations.
var firstName, lastName;
var price, discount, fullPrice;

firstName = "John";
lastName = "Doe";

price = 19.90;
discount = 0.10;

fullPrice = price * 100 / discount;
This also goes for variables in loops:
var i;
for (i = 0; i < 5; i++)
Note Since JavaScript moves the declarations to the top anyway (JavaScript hoisting), it is always a good rule.

28.Never Declare Numbers, Strings, or Booleans as Objects

Always treat numbers, strings, or booleans as primitive values. Not as objects.
Declaring numbers, strings, or booleans as objects, slows down execution speed, and produces nasty side effects:

Example

var x = "John";        
var y = new String("John");
(x === y) // is false because x is a string and y is an object.



29.Don't Use new Object()

  • Use {} instead of new Object()
  • Use "" instead of new String()
  • Use 0 instead of new Number()
  • Use false instead of new Boolean()
  • Use [] instead of new Array()
  • Use /(:)/ instead of new RegExp()
  • Use function (){} instead of new function()

Example

var x1 = {};           // new object var x2 = "";           // new primitive string var x3 = 0;            // new primitive number var x4 = false;        // new primitive boolean var x5 = [];           // new array object var x6 = /()/;         // new regexp object var x7 = function(){}; // new function object



29.Beware of Automatic Type Conversions

Beware that numbers can accidentally be converted to strings or NaN (Not a Number).
JavaScript is loosely typed. A variable can contain different data types, and a variable can change its data type:

Example

var x = "Hello";     // typeof x is a string x = 5;               // changes typeof x to a number

Example

var x = 5 + 7;       // x.valueOf() is 12,  typeof x is a number var x = 5 + "7";     // x.valueOf() is 57,  typeof x is a string var x = "5" + 7;     // x.valueOf() is 57,  typeof x is a string var x = 5 - 7;       // x.valueOf() is -2,  typeof x is a number var x = 5 - "7";     // x.valueOf() is -2,  typeof x is a number var x = "5" - 7;     // x.valueOf() is -2,  typeof x is a number var x = 5 - "x";     // x.valueOf() is NaN, typeof x is a number

Example

"Hello" - "Dolly"    // returns NaN



30.Use === Comparison

The == comparison operator always converts (to matching types) before comparison.
The === operator forces comparison of values and type:

Example

0 == "";        // true 1 == "1";       // true 1 == true;      // true
0 === "";       // false 1 === "1";      // false 1 === true;     // false



31. Use Parameter Defaults

If a function is called with a missing argument, the value of the missing argument is set to undefined.
Undefined values can break your code. It is a good habit to assign default values to arguments.

Example

function myFunction(x, y) {
    if (y === undefined) {
        y = 0;
    }
}
Or, even simpler:
function myFunction(x, y) {
    y = y || 0;
}


32. Avoid Using eval()

The eval() function is used to run text as code. In almost all cases, it should not be necessary to use it.
Because it allows arbitrary code to be run, it also represents a security problem.

33. Reduce Activity in Loops

Loops are often used in programming.
Every statement inside a loop will be executed for each iteration of the loop.
Search for statements or assignments that can be placed outside the loop.

34. Reduce DOM Access

Accessing the HTML DOM is very slow, compared to other JavaScript statements.
If you expect to access a DOM element several times, access it once, and use it as a local variable:

Example

obj = document.getElementByID("demo");
obj.innerHTML = "Hello";



35. Reduce DOM Size

Keep the number of elements in the HTML DOM small.
This will always improve page loading, and speed up rendering (page display), especially on smaller devices.
Every attempt to search the DOM (like getElementsByTagName) is will benefit from a smaller DOM.

36. Avoid Unnecessary Variables

Don't create new variables if you don't plan to save values.
Often you can replace code like this:
var fullName = firstName + " " + lastName;
document.getElementById("demo").innerHTML = fullName;
With this:
document.getElementById("demo").innerHTML = firstName + " " + lastName


37. Delay JavaScript Loading

Putting your scripts at the bottom of the page body, lets the browser load the page first.
While a script is downloading, the browser will not start any other downloads. In addition all parsing and rendering activity might be blocked.
Note The HTTP specification defines that browsers should not download more than two components in parallel.
An alternative is to use defer="true" in the script tag. The defer attribute specifies that the script should be executed before the page has finished parsing, but it only works for external scripts.
If possible, you can add your script to the page by code, after the page has loaded:

Example

<script>
window.onload = downScripts;

function downScripts() {
    var element = document.createElement("script");
    element.src = "myScript.js";
    document.body.appendChild(element);
}
</script>


38. Avoid Using with

Avoid using the with keyword. It has a negative effect on speed. It also clutters up JavaScript scopes.
The with keyword is not allowed in strict mode.

39. Create a Self-calling Function

This is often called a Self-Invoked Anonymous Function or Immediately Invoked Function Expression (IIFE). It is a function that executes automatically when you create it, and has the following form:
(function(){
    // some private code that will be executed automatically
})();  
(function(a,b){
    var result = a+b;
    return result;
})(10,20)
 
40 – A string trim function

The classic trim function of Java, C#, PHP and many other language that remove whitespace from a string doesn’t exist in JavaScript, so we could add it to the String object.
String.prototype.trim = function(){return this.replace(/^\s+|\s+$/g, "");};  
A native implementation of the trim() function is available in the recent JavaScript engines.

41 – Append an array to another array

var array1 = [12 , "foo" , {name "Joe"} , -2458];

var array2 = ["Doe" , 555 , 100];
Array.prototype.push.apply(array1, array2);
/* array1 will be equal to  [12 , "foo" , {name "Joe"} , -2458 , "Doe" , 555 , 100] */
 
42 – Transform the arguments object into an array

var argArray = Array.prototype.slice.call(arguments);
 
43 – Verify that a given argument is a number

function isNumber(n){
    return !isNaN(parseFloat(n)) && isFinite(n);
}
 
44 – Verify that a given argument is an array

function isArray(obj){
    return Object.prototype.toString.call(obj) === '[object Array]' ;
}
 
Note that if the toString() method is overridden, you will not get the expected result using this trick.
Or use…
Array.isArray(obj); // its a new Array method
You could also use instanceof if you are not working with multiple frames. However, if you have many contexts, you will get a wrong result.
var myFrame = document.createElement('iframe');
document.body.appendChild(myFrame);

var myArray = window.frames[window.frames.length-1].Array;
var arr = new myArray(a,b,10); // [a,b,10]  

// instanceof will not work correctly, myArray loses his constructor 
// constructor is not shared between frames
arr instanceof Array; // false
 
45 – Get the max or the min in an array of numbers

var  numbers = [5, 458 , 120 , -215 , 228 , 400 , 122205, -85411]; 
var maxInNumbers = Math.max.apply(Math, numbers); 
var minInNumbers = Math.min.apply(Math, numbers);
 
46 – Empty an array

var myArray = [12 , 222 , 1000 ];  
myArray.length = 0; // myArray will be equal to [].
 
47 – Don’t use delete to remove an item from array

Use splice instead of using delete to delete an item from an array. Using delete replaces the item with undefined instead of the removing it from the array.
Instead of…
var items = [12, 548 ,'a' , 2 , 5478 , 'foo' , 8852, , 'Doe' ,2154 , 119 ]; 
items.length; // return 11 
delete items[3]; // return true 
items.length; // return 11 
/* items will be equal to [12, 548, "a", undefined × 1, 5478, "foo", 8852, undefined × 1, "Doe", 2154,       119]   */
Use…
var items = [12, 548 ,'a' , 2 , 5478 , 'foo' , 8852, , 'Doe' ,2154 , 119 ]; 
items.length; // return 11 
items.splice(3,1) ; 
items.length; // return 10 
/* items will be equal to [12, 548, "a", 5478, "foo", 8852, undefined × 1, "Doe", 2154,       119]   */
The delete method should be used to delete an object property.

48 – Truncate an array using length

Like the previous example of emptying an array, we truncate it using the length property.
var myArray = [12 , 222 , 1000 , 124 , 98 , 10 ];  
myArray.length = 4; // myArray will be equal to [12 , 222 , 1000 , 124].
As a bonus, if you set the array length to a higher value, the length will be changed and new items will be added with undefined as a value. The array length is not a read only property.
myArray.length = 10; // the new array length is 10 
myArray[myArray.length - 1] ; // undefined
 
49 – Use logical AND/ OR for conditions
var foo = 10;  
foo == 10 && doSomething(); // is the same thing as if (foo == 10) doSomething(); 
foo == 5 || doSomething(); // is the same thing as if (foo != 5) doSomething();
The logical OR could also be used to set a default value for function argument.
function doSomething(arg1){ 
    arg1 = arg1 || 10; // arg1 will have 10 as a default value if it’s not already set
}
 
50 – Use the map() function method to loop through an array’s items

var squares = [1,2,3,4].map(function (val) {  
    return val * val;  
}); 
// squares will be equal to [1, 4, 9, 16] 
 
51 – Rounding number to N decimal place

var num =2.443242342;
num = num.toFixed(4);  // num will be equal to 2.4432
NOTE : the toFixed() function returns a string and not a number.

52 – Floating point problems

0.1 + 0.2 === 0.3 // is false 
9007199254740992 + 1 // is equal to 9007199254740992  
9007199254740992 + 2 // is equal to 9007199254740994
Why does this happen? 0.1 +0.2 is equal to 0.30000000000000004. What you need to know is that all JavaScript numbers are floating points represented internally in 64 bit binary according to the IEEE 754 standard.
You can use toFixed() and toPrecision() to resolve this problem.

53 – Check the properties of an object when using a for-in loop

This code snippet could be useful in order to avoid iterating through the properties from the object’s prototype.
for (var name in object) {  
    if (object.hasOwnProperty(name)) { 
        // do something with name                    
    }  
}
 
54 – Comma operator

var a = 0; 
var b = ( a++, 99 ); 
console.log(a);  // a will be equal to 1 
console.log(b);  // b is equal to 99
 
55 – Cache variables that need calculation or querying

In the case of a jQuery selector, we could cache the DOM element.
var navright = document.querySelector('#right'); 
var navleft = document.querySelector('#left'); 
var navup = document.querySelector('#up'); 
var navdown = document.querySelector('#down');
 
56 – Verify the argument before passing it to isFinite()

isFinite(0/0) ; // false 
isFinite("foo"); // false 
isFinite("10"); // true 
isFinite(10);   // true 
isFinite(undefined);  // false 
isFinite();   // false 
isFinite(null);  // true  !!! 
 
57 – Avoid negative indexes in arrays

var numbersArray = [1,2,3,4,5]; 
var from = numbersArray.indexOf("foo") ;  // from is equal to -1 
numbersArray.splice(from,2);    // will return [5]
Make sure that the arguments passed to splice are not negative.

58 – Serialization and deserialization (working with JSON)

var person = {name :'Saad', age : 26, department : {ID : 15, name : "R&D"} }; 
var stringFromPerson = JSON.stringify(person); 
/* stringFromPerson is equal to "{"name":"Saad","age":26,"department":{"ID":15,"name":"R&D"}}"   */ 
var personFromString = JSON.parse(stringFromPerson);  
/* personFromString is equal to person object  */
 
59 – Avoid the use of eval() or the Function constructor

Use of eval or the Function constructor are expensive operations as each time they are called script engine must convert source code to executable code.
var func1 = new Function(functionCode);
var func2 = eval(functionCode);
 
60 – Avoid using with() (The good part)

Using with() inserts a variable at the global scope. Thus, if another variable has the same name it could cause confusion and overwrite the value.

61 – Avoid using for-in loop for arrays

Instead of using…
var sum = 0;  
for (var i in arrayNumbers) {  
    sum += arrayNumbers[i];  
}
…it’s better to use…
var sum = 0;  
for (var i = 0, len = arrayNumbers.length; i < len; i++) {  
    sum += arrayNumbers[i];  
}
As a bonus, the instantiation of i and len is executed once because it’s in the first statement of the for loop. Thsi is faster than using…
for (var i = 0; i < arrayNumbers.length; i++)
Why? The length of the array arrayNumbers is recalculated every time the loop iterates.
NOTE : the issue of recalculating the length in each iteration was fixed in the latest JavaScript engines.

62 – Pass functions, not strings, to setTimeout() and setInterval()

If you pass a string into setTimeout() or setInterval(), the string will be evaluated the same way as with eval, which is slow. Instead of using…
setInterval('doSomethingPeriodically()', 1000);  
setTimeout('doSomethingAfterFiveSeconds()', 5000);
…use…
setInterval(doSomethingPeriodically, 1000);  
setTimeout(doSomethingAfterFiveSeconds, 5000);
 
63 – Use a switch/case statement instead of a series of if/else

Using switch/case is faster when there are more than 2 cases, and it is more elegant (better organized code). Avoid using it when you have more than 10 cases.

64 – Use switch/case statement with numeric ranges

Using a switch/case statement with numeric ranges is possible with this trick.
function getCategory(age) {  
    var category = "";  
    switch (true) {  
        case isNaN(age):  
            category = "not an age";  
            break;  
        case (age >= 50):  
            category = "Old";  
            break;  
        case (age <= 20):  
            category = "Baby";  
            break;  
        default:  
            category = "Young";  
            break;  
    };  
    return category;  
}  
getCategory(5);  // will return "Baby"
 
65 – Create an object whose prototype is a given object

It’s possible to write a function that creates an object whose prototype is the given argument like this…
function clone(object) {  
    function OneShotConstructor(){}; 
    OneShotConstructor.prototype= object;  
    return new OneShotConstructor(); 
} 
clone(Array).prototype ;  // []
 
66 – An HTML escaper function

function escapeHTML(text) {  
    var replacements= {"<": "&lt;", ">": "&gt;","&": "&amp;", "\"": "&quot;"};                      
    return text.replace(/[<>&"]/g, function(character) {  
        return replacements[character];  
    }); 
}
 
67 – Avoid using try-catch-finally inside a loop

The try-catch-finally construct creates a new variable in the current scope at runtime each time the catch clause is executed where the caught exception object is assigned to a variable.
Instead of using…
var object = ['foo', 'bar'], i;  
for (i = 0, len = object.length; i <len; i++) {  
    try {  
        // do something that throws an exception 
    }  
    catch (e) {   
        // handle exception  
    } 
}
…use…
var object = ['foo', 'bar'], i;  
try { 
    for (i = 0, len = object.length; i <len; i++) {  
        // do something that throws an exception 
    } 
} 
catch (e) {   
    // handle exception  
} 
 
68 – Set timeouts to XMLHttpRequests

You could abort the connection if an XHR takes a long time (for example, due to a network issue), by using setTimeout() with the XHR call.
var xhr = new XMLHttpRequest (); 
xhr.onreadystatechange = function () {  
    if (this.readyState == 4) {  
        clearTimeout(timeout);  
        // do something with response data 
    }  
}  
var timeout = setTimeout( function () {  
    xhr.abort(); // call error callback  
}, 60*1000 /* timeout after a minute */ ); 
xhr.open('GET', url, true);  

xhr.send();
As a bonus, you should generally avoid synchronous XHR calls completely.

69 – Deal with WebSocket timeout

Generally when a WebSocket connection is established, a server could time out your connection after 30 seconds of inactivity. The firewall could also time out the connection after a period of inactivity.
To deal with the timeout issue you could send an empty message to the server periodically. To do this, add these two functions to your code: one to keep alive the connection and the other one to cancel the keep alive. Using this trick, you’ll control the timeout.
Add a timerID
var timerID = 0; 
function keepAlive() { 
    var timeout = 15000;  
    if (webSocket.readyState == webSocket.OPEN) {  
        webSocket.send('');  
    }  
    timerId = setTimeout(keepAlive, timeout);  
}  
function cancelKeepAlive() {  
    if (timerId) {  
        cancelTimeout(timerId);  
    }  
}
The keepAlive() function should be added at the end of the onOpen() method of the webSocket connection and the cancelKeepAlive() at the end of the onClose() method.

70 – Keep in mind that primitive operations can be faster than function calls

For example, instead of using…
var min = Math.min(a,b); 
A.push(v);
…use…
var min = a < b ? a : b; 
A[A.length] = v;
 
71. Use Semicolons for line termination 
 
72. – Don’t forget to use a code beautifier when coding. Use JSLint and minification (JSMin, for example) before going live.
 

No comments:

Post a Comment