Please, share your tips and tricks related to JavaScript coding. The ones which make code more elegant and faster.
See also:
-
Use of a library such as jQuery
-
Check if an object is not empty
// JavaScript 1.5 function isNotEmpty(obj) { for (var tmp in obj) return true } // JavaScript 1.8 function isNotEmpty(obj) obj.__count__;Transform the arguments object into an array
function foo() { Array.slice(arguments); // is ['aa',11] } foo('aa', 11);JavaScript Minifier / comment remover
var script = new Script('var a; /* this is a variable */ var b; ' + '// another variable'); Print( script.toString() ); // prints: // var a; // var b;Singleton pattern
function MySingletonClass() { if ( arguments.callee._singletonInstance ) return arguments.callee._singletonInstance; arguments.callee._singletonInstance = this; this.Foo = function() { // ... } } var a = new MySingletonClass(); var b = MySingletonClass(); Print( a === b ); // prints: trueFactory method pattern
Complex = new function() { function Complex(a, b) { // ... } this.fromCartesian = function(real, mag) { return new Complex(real, imag); } this.fromPolar = function(rho, theta) { return new Complex(rho * Math.cos(theta), rho * Math.sin(theta)); }} var c = Complex.fromPolar(1, Math.pi); // Same as fromCartesian(-1, 0);Use Functions as an Object
function Counter() { if ( !arguments.callee.count ) { arguments.callee.count = 0; } return arguments.callee.count++; } Print( Counter() ); // prints: 0 Print( Counter() ); // prints: 1 Print( Counter() ); // prints: 2Listen a property for changes
function onFooChange( id, oldval, newval ) { Print( id + " property changed from " + oldval + " to " + newval ); return newval; } var o = { foo:5 }; o.watch( 'foo', onFooChange ); o.foo = 6; delete o.foo; o.foo = 7; o.unwatch('foo'); o.foo = 8; // prints: // foo property changed from 5 to 6 // foo property changed from undefined to 7bobince : Accessing ‘slice’ directly through the Array object instead of Array.prototype is non-standard and won't work everywhere. Instead use “Array.prototype.slice.call(arraylike, begin[, end])”.bobince : (However technically even this usage is non-standard as Array methods are not defined to work on non-Array objects, and it would depend on the internal implementation whether it was OK or not. However, since this trick is quite widely used it will probably continue to be OK in practice.)KooiInc : Array.prototype.slice.call(arraylike, begin[, end]) seldom works with IE collections (like stylesheet rules)IonuČ› G. Stan : What's that Singleton pattern in there? What's wrong with object literals?Sander Versluys : Although not all of them are clear to me why to use them in javascript, some look like really good examples and stuff to think about! thanks ;-) -
Trick
Use the "javascript:" protocol
Youc can store js code in a bookmark so in can be used in any Web site you visit. It's called "bookmarklet", and it's a hell of a fun :-)
Some bookmarklets for web dev.
Javascript to enhance IE
If you are like most of the Web designers, you want IE6 (en 5, 4, etc) to die. But there is a way to make him interpret the CSS just like IE7, which is much better.
Use conditional comments to load a JS librairy that will tweak his behavior :
<!--[if lt IE 7]> <script src="http://ie7-js.googlecode.com/svn/version/2.0(beta3)/IE7.js" type="text/javascript"></script> <![endif]-->Now, you can deal more easily with IE, and not care about the version. IE6 users will have to wait some seconds for JS to load the first visit, that's all. And for those who have IE6 and JS disable, well, they will see a crappy Website but they are masochist anyway ;-)
Iterate over Arrays using "for in"
I think everybody know the usefullness of the "for in" loop :
// creating an object (the short way, to use it like a hashmap) var diner = { "fruit":"apple" "veggetable"="bean" } // looping over its properties for (meal_name in diner ) { document.write(meal_name+"<br \n>"); }Result :
fruit veggetableBut there is more. Since you can use an object like an associative array, you can process keys and values, just like a foreach loop :
// looping over its properties and values for (meal_name in diner ) { document.write(meal_name+" : "+diner[meal_name]+"<br \n>"); }Result :
fruit : apple veggetable : beanAnd since Array are objects too, you can iterate other array the exact same way :
var my_array = ['a', 'b', 'c']; for (index in my_array ) { document.write(index+" : "+my_array[index]+"<br \n>"); }Result :
0 : a 1 : b 3 : cRemove easily an known element from an array
var arr = ['a', 'b', 'c', 'd']; var pos = arr.indexOf('c'); pos > -1 && arr.splice( pos, 1 );Best practice
Always use the second argument parseInt()
parseInt(string, radix)Indeed, parseInt() converts a string to int, but will try to guess the numeral system if you omit radix, following the rules :
- If the string begins with "0x", the radix is 16 (hexadecimal)
- If the string begins with "0", the radix is 8 (octal). This feature is deprecated
- If the string begins with any other value, the radix is 10 (decimal)
Most of the time, you will use :
var my_int = parseInt(my_string, 10);Check the property ownership while using "for in"
"for in" iterate other the object properties, but the properties can be ineritated from the object prototype. Since anyone can dynamically alter prototypes, on sensible objects you'd better check if the property is its own before using it :
for (var name in object) { if (object.hasOwnProperty(name)) { } }Steve Harrison : Yes, I learnt that "parseInt" best practice the hard way!Sander Versluys : Again, great suggestions, this is an awesome question! txn -
prototype extension of native objects for utility methods
A couple of my favourites:
String.prototype.reverse = function () { return this.split('').reverse().join(''); }; Date.prototype.copy = function () { return new Date(this); }; -
Remedial work. Use prototype-based monkey-patching to add new standardised features to old and crappy browsers.
// Add JavaScript-1.6 array features if not supported natively // if (![].indexOf) { Array.prototype.indexOf= function(find) { for (var i= 0; i<this.length; i++) if (this[i]==find) return i; return -1; }; } if (![].map) { Array.prototype.map= function(fn) { var out= []; for (var i= 0; i<this.length; i++) out.push(fn(this[i])); return out; }; } if (![].filter) { Array.prototype.filter= function(fn) { var out= []; for (var i= 0; i<this.length; i++) if (fn(this[i])) out.push(this[i]); return out; }; } // Add ECMAScript-3.1 method binding if not supported natively. // Note, uses a direct reference, which if assigned to an event // handler will cause reference loops/memory leaking in IE6. // (Could add a lookup-map cycle-breaker to improve this in the // future.) // if (!Function.prototype.bind) { Function.prototype.bind= function(owner/* {, args} */) { var method= this; var args= Array_fromSequence(arguments).slice(1); return function() { var allargs= args.length==0? arguments : arguments.length==0? args : Array_fromSequence(args, arguments); return method.apply(owner, allargs); }; }; } // Compile an Array from one or more Array-like sequences (arguments, NodeList...) // Used by Function.bind. // Array_fromSequence= function(/* args */) { var arr= []; for (var argi= 0; argi<arguments.length; argi++) for (var itemi= 0; itemi<arguments[argi].length; itemi++) arr.push(arguments[argi][itemi]); return arr; };Generally, it's worth being conservative with the prototype patching, because changes you make will affect all scripts on the page, potentially causing bad interactions. Adding arbitrary methods can go wrong when another script tries to use the same member name for another purpose. But fixing up browsers to comply with new standards is generally harmless.
Tchalvak : If you're going to go that far, using a framework and sharing work seeems like a better way to go. -
Logical operators tricks
var a = 5; a == 5 && Print( 'a is 5 \n' ); a == 7 || Print( 'a is not 7 \n' ); // prints: // a is 5 // a is not 7Remove an item by value in an Array object
var arr = ['a', 'b', 'c', 'd']; var pos = arr.indexOf( 'c' ); pos > -1 && arr.splice( pos, 1 ); Print( arr ); // prints: a,b,dshuffle the Array
var list = [1,2,3,4,5,6,7,8,9]; list = list.sort(function() Math.random() > 0.5 ? 1 : -1); Print( list ); // prints something like: 4,3,1,2,9,5,6,7,8Optional named function arguments
function foo({ name:name, project:project}) { Print( project ); Print( name ); } foo({ name:'web', project:'so' }) foo({ project:'so', name:'web'})Might not work in FF. See Comments.
Floating to integer
(123.345456).toFixed(); // is: 123 typeof (1.5).toFixed(); // is: stringChange the primitive value an object with valueOf
function foo() { this.valueOf = function() { return 'this is my value'; }} var bar = new foo(); Print( bar ); // prints: this is my valueNew object override
function foo() { return new Array(5,6,7); } var bar = new foo(); bar.length // is 3Nested functions and closures
function CreateAdder( add ) { return function( value ) { return value + add; }} // usage: var myAdder5 = CreateAdder( 5 ); var myAdder6 = CreateAdder( 6 ); Print( myAdder5( 2 ) ); // prints 7 Print( myAdder6( 4 ) ); // prints 10SyntaxError
Raised when a syntax error occurs while parsing code in
eval()try { eval('1 + * 5'); // will rise a SyntaxError exception } catch( ex ) { Print( ex.constructor == SyntaxError ); // Prints true }ReferenceError
Raised when de-referencing an invalid reference.
try { fooBar(); // will rise a ReferenceError exception } catch( ex ) { Print( ex.constructor == ReferenceError ); // Prints true }kentaromiura : the latest trick work only in FF. a similar cross-browser trick can be: function foo(x){ with(x){ alert( project ); alert( naame ); } } foo({ naame:'web', project:'so' }) foo({ project:'so', naame:'web'}) but with statement must be used carefullyKoistya Navin : @kentaromiura, good point. Thanks. -
Solid type-checking function:
function type(v) { if (v === null) { return 'null'; } if (typeof v === 'undefined') { return 'undefined'; } return Object.prototype.toString.call(v).match(/\s(.+?)\]/)[1]. toLowerCase(); } // Usage: type({}); // 'object' type([]); // 'array' type(333); // 'number'Find the maximum or minimum value in an array of numbers:
var arrNumbers = [1,4,7,3,5,9,3,2]; Math.max.apply(null, arrNumbers); // 9 Math.min.apply(null, arrNumbers); // 1 -
I often see people that doesn't have any clue of how javascript really works. So I wish to point out this document: javascript prototypal inheritance
Sorry, too many time I see people call new without actually fully understanding what they are really doing in javascript.
-
Test if an image has loaded:
function hasLoaded ( img ) { return img.complete && img.naturalWidth !== 0; }Dec to hex / hex to dec:
Amazingly people still try to do this computationally:
// number to hexadecimal '0x' + Number( 15 ).toString( 16 ); // hexadecimal to number parseInt( String( '8f3a5' ), 16 );String repeat:
Perhaps not be the fastest way of doing this, but a nifty approach I picked up somewhere:
String.prototype.repeat = function ( n ) { return new Array( (n || 1) + 1 ).join( this ); }Get number signature with boolean math operations:
Not very useful, but an interesting demonstration of booleans vs. the +/- operators. I've used it in GPS coordinates formating:
function signature ( n ) { return ['-','','+'][ -(0 > n) +(0 < n) +1 ]; }Quick & easy namespaces:
String.prototype.namespace = function ( obj ) { var c, b = this.split('.'), p = window; while (c = b.shift()) { p = (p[c] = (p[c] || {})); } if (typeof obj === 'object') { for (var k in obj) { p[k] = obj[k]; } } return p; };Doesn't necessarily have to sit on the string prototype, I just think it's neat for the purposes of this example:
"com.stackoverflow.somemodule".namespace({ init: function () { // some code } }) -
String format like function:
String.prototype.format = function(){ var pattern = /\{\d+\}/g; var args = arguments; return this.replace(pattern, function(capture){ return args[capture.match(/\d+/)]; }); }//Example
var a = 'hello, {0}'; var b = a.format('world!');
0 comments:
Post a Comment