= Functional JavaScript Development with Prototype by Ben Nolan function(i){return i}; == About Ben Nolan Blog: www.bennolan.com There might be some people who talk offense by my Javascript techniques Been coding Javascript for 4-5 years Developer of Behaviour.js and Groupwiski Promot functional-ish javascript == Why Functional? * Many small functions - bugs are reduced this way * Code is more self-descriptive, promotes teamwork * Testing is simplified * There is some really good testing stuff === Why not functional? * Code looks obtuse to new developers return function(i){return this.calc(i)}.bind(this); * Protoype's function extensions are slower than native loops == Lambdas and Binding === Anonymous functions / Lambdas A function without a name Benefits: * Don't have to pollute your scope with lots of function names * Functions have their own scope while(true) { var x = 5; // not locally scoped } function(){ var x = 'a'; // locally scoped } * Easier to make idempotent functions - no stomping on other variables === The bind Function * Bind is required because Javascript doesn't call functions automatically in the right scope function x() { alert(this); } x(); // [object Window] y = x.bind('Banana!'); y(); // [string Banana!] * You can call bind on all variables * Binding to "this" Wrong: MyClass.prototype = { initialize: function( ){ document.body.onclick = this.onclick() // Wrong! Calls the function straight away } } *** MyClass.prototype = { initialize: function( ){ document.body.onclick = this.onclick }, onclick: function() { this.doSomething(); }, doSomething: function(){ // Called inside the Window scope } } Right: MyClass.prototype = { initialize: function( ){ document.body.onclick = this.onclick.bind(this); }, onclick: function() { this.doSomething(); }, doSomething: function(){ // Called inside the scope of the object } } === Some idioms * Smaller functions are better * Idempotent functions are the ideal * Functions that don't alter the dom or the properties of an object - they just return a value * Pragmatism not idealism * Start with dirty big function - refactor to smaller ones == Enumerable functions * Prototype introduces ruby-ish enumerable functions to javascript * Convert a javascript array to an enumerable artray with the $A() function * Firefox modifies the original array * IE creates a new one === Example Old-style js: function getInsidesOf(ary) { car outp = new Array; for(var i in ary) {outp.push(i.innerHTML);} return outp } Functional js: function getInsidesOf(ary) { return $A(ary).pluck('innerHTML'); } === Cool enum methods * Invoke(methodName) * invokes methods on each array * Pluck(propertyName) * inGroups(integer) [1,2,3,4] => [[1,2], [3,4]] == Lambdas and Enum Simplest example: return $A([1,2,3,4,5]).map( function(i) { return i+1 } ); // returns [2,3,4,5,6] Filtering Elements * Get an array of selected checkboxes $$('input[type=select]').select(function(el)){ // Like the ruby grep function return el.selected; } Updating elements * Empty the innerHTML of all A elements $$('a').each(function(el){ el.update(''); }) == How I structure apps * Use OO-style classes (class.create and object.extend) * Try and use a minimum of private properties in my classes - introspect the dom instead * No need to keep your own copy and get out of sync * Try and use idempotent functions == Example code * I have a rich-text-editor written with Prototype * Browsers use different markup Convert bolded spans to tags $$("span").each(function(el){ if(el.getStyle('font-weight')=='bold') el.convertTo('B'); }); Find an element which has the style: "display:block" return this.getAncestors().find(function(el){ return el.getStyle('display') == 'block'; }); == Take aways * Use many small functions that are idempotent * Use enumrable functions * Use anonymoous functions liberally * See prototypejs.org for more information Uses Prototype TestUnit for Javascript testing