Functional Javascript

6,523 views

Published on

Functional javascript presentation Ben Nolan showed at railsconf europe 2007.

Published in: Technology

Functional Javascript

  1. 1. Functional Javascript function(i){return i}; Ben Nolan
  2. 2. About me • New Zealander living in Munich • Blog at bennolan.com • Developer of Behaviour.js and Groupswiki • I promote functional-ish javascript
  3. 3. Target Audience • Intermediate javascript developers that haven’t used prototypes enumerable functions. • People that don’t quite follow .bind and anonymous functions(){}
  4. 4. Table of Contents • Why Functional? • Lambdas and binding • Enumerable functions • Examples • Takeaways
  5. 5. Why Functional? • Many small functions - Bugs are reduced by this methodology • Code is more self-descriptive, promotes teamwork • Testing is simplified
  6. 6. Why not functional? • Code looks obtuse to new developers return function(i){return this.calc(i)}.bind(this); • Prototype’s functional extensions are slower than native loops. This is getting better in later versions of prototype.
  7. 7. Anonymous functions • Also known as Lambdas alert(function(){ return “hello”; }()); • Simply put - it’s a function that doesn’t have a name
  8. 8. Benefit of the Lambda • Don’t have to pollute your scope with lots of function names. function mysort(x,y){return x<=>y}; ary.sort(mysort); or ary.sort(function(x,y){return x<>y});
  9. 9. Benefit of the Lambda • 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
  10. 10. The bind Function • Bind is required because Javascript doesn’t automatically call methods in the correct scope • Bind returns an anonymous function that calls a method in the scope of the argument • (It’s a form of currying)
  11. 11. Binding to a Banana function x(){ alert(this); } x(); // [object Window] y = x.bind('Banana!') y(); // [string Banana!]
  12. 12. Binding to “this” Wrong: MyClass.prototype = { initialize : function(){ document.body.onclick = this.onclick(); }, onclick : function(){ this.doSomething(); }, doSomething : function(){ } }
  13. 13. Binding to “this” Wrong: MyClass.prototype = { initialize : function(){ document.body.onclick = this.onclick; }, onclick : function(){ this.doSomething(); }, doSomething : function(){ } }
  14. 14. Binding to “this” Right: MyClass.prototype = { initialize : function(){ document.body.onclick = this.onclick.bind(this); }, onclick : function(){ this.doSomething(); }, doSomething : function(){ } }
  15. 15. Some idioms • Smaller functions are better. Less code means it’s easier to inspect and easier to test. Use lots of small functions.
  16. 16. Some idioms • Idempotent functions are the ideal. ie Functions that don’t alter the dom or the properties of a object - they just return a value.
  17. 17. Some idioms • Pragmatism not idealism. Start with dirty big functions - refactor to smaller nicer functions as you can.
  18. 18. The Enumerables • Prototype introduces ruby-ish enumerable functions to javascript. • Convert a javascript array to an enumerable array with the $A() function. $A([1,2,3]);
  19. 19. Enumerable Example • Old-style javascript: function getInsidesOf(ary){ var outp = new Array; for (i in ary){outp.push(i.innerHTML);} return outp; } (nb: this code alters the variable i in the global namespace - an easy mistake to make)
  20. 20. Enumerable Example • Using functional Javascript: function getInsidesOf(ary){ return $A(ary).pluck(‘innerHTML’); }
  21. 21. Cool enum. methods • Invoke(methodName) elements in the array invokes methodName on each • Pluck(propertyName) gathered from each element returns an array of the property in the array • inGroupsOf(integer) eg: [1,2,3,4,5] -> [[1,2],[3,4],[5]]
  22. 22. Enums and lambdas • The most powerful enum methods require a function as an argument. • You can sort, filter and order with these tools.
  23. 23. Lambdas and Enum. • Simplest example: return $A([1,2,3,4,5]).map( function(i){ return i+1; } }); // Returns [2,3,4,5,6]
  24. 24. Lambdas and Enum. Create an • Simplest example: array with enum extensions return $A([1,2,3,4,5]).map( function(i){ return i+1; } }); // Returns [2,3,4,5,6]
  25. 25. Lambdas and Enum. • Simplest example: return $A([1,2,3,4,5]).map( Anonymous function(i){ function return i+1; } }); // Returns [2,3,4,5,6]
  26. 26. Filtering Elements • Get an array of selected checkboxes: $$(‘input[type=checkbox]’).select(function(el){ return el.selected; });
  27. 27. Filtering Elements Get an array of input tags • $$(‘input[type=checkbox]’).select(function(el){ return el.selected; });
  28. 28. Filtering Elements Call the select function • $$(‘input[type=checkbox]’).select(function(el){ return el.selected; });
  29. 29. Filtering Elements Pass a function as an argument • $$(‘input[type=checkbox]’).select(function(el){ return el.selected; });
  30. 30. Updating Elements • Empty the innerHTML of all A elements: $$(‘a’).each(function(el){ el.update(‘’); });
  31. 31. 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 • Try and use idempotent functions
  32. 32. Example code • I have a rich-text-editor written with Prototype. • Browsers use different markup IE Safari Mozilla strong <span style=..> em
  33. 33. Example code • Convert bolded spans to <b> tags $$(quot;spanquot;).each(function(el){ if(el.getStyle('font-weight')=='bold'){ el.convertTo(‘B’); } });
  34. 34. Example code • Find an element which has the style: “display:block” return this.getAncestors().find(function(el){ return el.getStyle('display') == 'block'; });
  35. 35. Take aways • Use many small functions that are idempotent • Use enumerable functions • Use anonymous functions liberally • See prototypejs.org for more information

×