Javascript tips and tricks I’ve found useful. Contributions welcome – just visit the source, make sure you are logged in and hit edit, or, fork and pull.
Table of Contents
Object Operations
Deep Copy
Warning: full deep copy is hard. The following are only appropriate for “simple” objects.
JQuery
Copy (clone) in javascript with JQuery::
// Shallow copy
var newObject = jQuery.extend({}, oldObject);
// Deep copy
var newObject = jQuery.extend(true, {}, oldObject);
Underscore
Note underscore does not do a deep copy at all – it will only do copy on first level attributes::
_.extend({}, myobject);
JSON
Deserialize to and from JSON (warning: not at all performant!)::
var newobj = JSON.parse(JSON.stringify(oldobj));
Check if a variable is undefined
// The typeof operator always returns a string!
if (typeof(variable) === "undefined") {
// do something
}
Simple Inheritance in Javascript
John Resig’s original
From http://ejohn.org/blog/simple-javascript-inheritance/
/* Simple JavaScript Inheritance
* By John Resig http://ejohn.org/
* MIT Licensed.
*/
// Inspired by base2 and Prototype
(function(){
var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
// The base Class implementation (does nothing)
this.Class = function(){};
// Create a new Class that inherits from this class
Class.extend = function(prop) {
var _super = this.prototype;
// Instantiate a base class (but only create the instance,
// don't run the init constructor)
initializing = true;
var prototype = new this();
initializing = false;
// Copy the properties over onto the new prototype
for (var name in prop) {
// Check if we're overwriting an existing function
prototype[name] = typeof prop[name] == "function" &&
typeof _super[name] == "function" && fnTest.test(prop[name]) ?
(function(name, fn){
return function() {
var tmp = this._super;
// Add a new ._super() method that is the same method
// but on the super-class
this._super = _super[name];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(name, prop[name]) :
prop[name];
}
// The dummy class constructor
function Class() {
// All construction is actually done in the init method
if ( !initializing && this.init )
this.init.apply(this, arguments);
}
// Populate our constructed prototype object
Class.prototype = prototype;
// Enforce the constructor to be what we expect
Class.prototype.constructor = Class;
// And make this class extendable
Class.extend = arguments.callee;
return Class;
};
})();
Usage::
var Person = Class.extend({
init: function(isDancing){
this.dancing = isDancing;
}
});
var Ninja = Person.extend({
init: function(){
this._super( false );
}
});
var p = new Person(true);
p.dancing; // => true
var n = new Ninja();
n.dancing; // => false
Steffen Rusitchka version
/* Steffen Rusitchka version
* <http://www.ruzee.com/blog/2008/12/javascript-inheritance-via-prototypes-and-closures>
* Creative Commons Attribution licensed
*/
(function(){
var isFn = function(fn) { return typeof fn == "function"; };
PClass = function(){};
PClass.create = function(proto) {
var k = function(magic) { // call init only if there's no magic cookie
if (magic != isFn && isFn(this.init)) this.init.apply(this, arguments);
};
k.prototype = new this(isFn); // use our private method as magic cookie
for (key in proto) (function(fn, sfn){ // create a closure
k.prototype[key] = !isFn(fn) || !isFn(sfn) ? fn : // add _super method
function() { this._super = sfn; return fn.apply(this, arguments); };
})(proto[key], k.prototype[key]);
k.prototype.constructor = k;
k.extend = this.extend || this.create;
return k;
};
})();
Usage::
var X = PClass.create({
val: 1,
init: function(cv) {
this.cv = cv;
},
test: function() {
return [this.val, this.cv].join(", ");
}
});
var Y = X.extend({
val: 2,
init: function(cv, cv2) {
this._super(cv); this.cv2 = cv2;
},
test: function() {
return [this._super(), this.cv2].join(", ");
}
});
var x = new X(123);
var y = new Y(234, 567);
Test whether an object is of a certain type
Test whether it is an Array:
obj instanceof Array
Another method if constructor is present
if (output.constructor == Array) {
}
else if(output.constructor == Object) {
}
Test whether it is a string of other simple type:
typeof obj === 'string'
typeof obj === 'number'
typeof obj === 'boolean'
String functions
Strip / Trim
Available in most modern browsers at the .trim() function but not available in IE7!
mystring = mystring.replace(/^\s+|\s+$/g, '');
Contains
Test whether one string contains another. Solution is to use indexOf
. For example, to test whether myString contains ‘levin’:
myString.indexOf('levin') != -1
Ends With
Does a string end with the given suffix:
mystring.indexOf(suffix, mystring.length - suffix.length) !== -1;
Miscellaneous
Pretty-print JSON
JSON.stringify({a: "lorem", b: "ipsum"}, null, 4);
JSON.stringify({a: "lorem", b: "ipsum"}, null, '\t');
Parse a Query String
Parse a URL query string (?xyz=abc…) into a dictionary.
parseQueryString = function(q) {
if (!q) {
return {};
}
var urlParams = {},
e, d = function (s) {
return decodeURIComponent(s.replace(/\+/g, " "));
},
r = /([^&=]+)=?([^&]*)/g;
if (q && q.length && q[0] === '?') q = q.slice(1);
while (e = r.exec(q)) {
// TODO: have values be array as query string allow repetition of keys
urlParams[d(e[1])] = d(e[2]);
}
return urlParams;
};
Format Numbers Nicely
var formatAmount = function (num) {
var billion = 1000000000;
var million = 1000000;
var thousand = 1000;
var numabs = Math.abs(num);
if (numabs > billion) {
return num / billion + 'bn';
}
if (numabs > (million / 2)) {
return num / million + 'm';
}
if (numabs > thousand) {
return num / thousand + 'k';
} else {
return num;
}
};
var formatAmountWithCommas = function (num, decimalPlaces) {
if (decimalPlaces === undefined) {
decimalPlaces = 0;
}
num = num.toFixed(decimalPlaces);
x = num.split('.');
x1 = x[0];
x2 = x.length > 1 ? '.' + x[1] : '';
var rgx = /(\d+)(\d{3})/;
while (rgx.test(x1)) {
x1 = x1.replace(rgx, '$1' + ',' + '$2');
}
return x1 + x2;
};
Short Unique ID
function generateUIDNotMoreThan1million() {
return ("0000" + (Math.random()*Math.pow(36,4) << 0).toString(36)).substr(-4)
}
Sluggify - make a text string usable in a URL
See https://gist.github.com/rgrp/6853701 for more examples
// lowercase, replace ' ' by '-' and remove everything that is not alphanumeric, underscore or dash
var slug = title
.toLowerCase()
.replace(/ /g, '-')
.replace(/--+/g, '-')
.replace(/[^\w-]+/g, '')
;
Javscript Module Pattern
Readings:
Modules that work in NodeJS and the Browser
Have your normal (browser) JS code then do:
// export to NodeJS or RequireJS if they are present ...
var safeExport = function (publicMethods) {
// NodeJS
if (typeof module !== 'undefined' && module !== null) module.exports = publicMethods;
// RequireJS
if (typeof define === "function") define([], publicMethods);
};
// now setup the export
module = {publicFunc1: publicFunc1, publicFunc2: publicFun2};
safeExport(module)