Please, share your tips and tricks related to JavaScript coding. The ones which make code more elegant and faster.
See also:
Please, share your tips and tricks related to JavaScript coding. The ones which make code more elegant and faster.
See also:
// JavaScript 1.5
function isNotEmpty(obj) {
for (var tmp in obj)
return true
}
// JavaScript 1.8
function isNotEmpty(obj) obj.__count__;
function foo() {
Array.slice(arguments); // is ['aa',11]
}
foo('aa', 11);
var script = new Script('var a; /* this is a variable */ var b; ' +
'// another variable');
Print( script.toString() );
// prints:
// var a;
// var b;
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: true
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);
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: 2
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 7
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
veggetable
But 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 : bean
And 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 : c
Remove easily an known element from an array
var arr = ['a', 'b', 'c', 'd'];
var pos = arr.indexOf('c');
pos > -1 && arr.splice( pos, 1 );
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 :
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)) {
}
}
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.
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 7
var arr = ['a', 'b', 'c', 'd'];
var pos = arr.indexOf( 'c' );
pos > -1 && arr.splice( pos, 1 );
Print( arr ); // prints: a,b,d
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,8
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.
(123.345456).toFixed(); // is: 123
typeof (1.5).toFixed(); // is: string
function foo() {
this.valueOf = function() {
return 'this is my value';
}}
var bar = new foo();
Print( bar ); // prints: this is my value
function foo() {
return new Array(5,6,7);
}
var bar = new foo();
bar.length // is 3
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 10
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
}
Raised when de-referencing an invalid reference.
try {
fooBar(); // will rise a ReferenceError exception
} catch( ex ) {
Print( ex.constructor == ReferenceError ); // Prints true
}
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!');