Your SlideShare is downloading. ×
Exciting JavaScript - Part I
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Saving this for later?

Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime - even offline.

Text the download link to your phone

Standard text messaging rates apply

Exciting JavaScript - Part I

4,211
views

Published on

JavaScript and popular programming paradigms (OOP, AOP, FP, DSL). Overview of the language to see what tools we can leverage to reduce complexity of our projects. …

JavaScript and popular programming paradigms (OOP, AOP, FP, DSL). Overview of the language to see what tools we can leverage to reduce complexity of our projects.

This part goes over language features and looks at OOP and AOP with JavaScript.

The presentation was delivered at ClubAJAX on 2/2/2010.
Blog post: http://lazutkin.com/blog/2010/feb/5/exciting-js-1/
Continued in Part II: http://www.slideshare.net/elazutkin/exciting-javascript-part-ii

Published in: Technology

1 Comment
15 Likes
Statistics
Notes
No Downloads
Views
Total Views
4,211
On Slideshare
0
From Embeds
0
Number of Embeds
9
Actions
Shares
0
Downloads
217
Comments
1
Likes
15
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Exciting JavaScript What makes it unique, how to use it. Eugene Lazutkin Dallas, TX, ClubAjax on 2/2/2010 1
  • 2. Disclaimer • I will use JavaScript, JS, and ECMAScript interchangeably. • The material is mostly based on ECMAScript 3. 2
  • 3. Why JavaScript? • Browsers. • CommonJS (ex-ServerJS) is gaining steam. • CouchDB uses it to define “views”. • Node.js with its asynchronous event-based I/O is red hot. • An explosion of JavaScript run-time environments and libraries. 3
  • 4. JS the Language I • JavaScript packages a formidable set of tools we can leverage to reduce complexity. • While it doesn’t provide a direct support for some programming paradigms, it has proper tools for us to do it. 4
  • 5. JS the Language II • Following paradigms can be supported: • Object-oriented programming (OOP). • Functional programming (FP). • Aspect-oriented programming (AOP). • Event-driven programming (EDP). • Much more. 5
  • 6. JS the Language III • Let’s do an inventory of the language facilities: • To understand how JavaScript is different from other languages. • To understand what we can use to improve meta-programming techniques. 6
  • 7. Inventory Available tools. 7
  • 8. 1 st class functions • We can create them on the fly. • Anonymous function. • We can write them inline. • Function literals. 8
  • 9. Function examples I // “normal” function function double1(x){ return 2 * x; } // anonymous function var double2 = function(x){ return 2 * x; }; 9
  • 10. Function examples II // takes function as an argument function scale(f, x){ return f(x); } // returns a function function var makeDouble = function(){ return function(x){ return 2 * x; }; }; // combine them var result = scale(makeDouble, 5); 10
  • 11. Closures I • Closures are: • The most mysterious part of JavaScript. • The bane of beginners, and the source of most their errors. • The cornerstone of Functional Programming in JavaScript. 11
  • 12. Closures II • It is a function, which uses variables from its lexical environment. • JavaScript closure uses external variables by reference. • It can consume, and modify external objects by name. 12
  • 13. Closures: examples var a = 1; // available here: a function f1(x){ var b = 2; // available here: a, f1, b, x function f2(y){ var c = 3; // available here: a, f1, b, x, f2, c, y return a + b + c + x + y; } } 13
  • 14. var: fine points I • Only functions produce lexical scopes. • It doesn’t matter where var statement is encountered: a variable is available everywhere in the function body. • Initialization is performed at the point of declaration. 14
  • 15. var: fine points II function f(x){ var n = 5, acc = 0; // available here: f, x, n, acc, i, d, b for(var i = 0; i < n; ++i){ var d = 2 * i; acc += d; } // b is available here yet undefined var b = 1000; return t + b * x; } 15
  • 16. Closures vs. Pure • Pure functions: • Stateless. • Have no side effects. • Operate only on their arguments. • Always return the same value for the same arguments. 16
  • 17. Why pure? • Theoretically: • Easier to analyze the program for correctness. • Code can be rearranged and optimized by compilers. • Opens up other techniques like lazy evaluations. 17
  • 18. Practical closures I // generate unique DOM ID var uniqId = (function(){ // truly private variables var prefix = “uniq_”, n = 0; return function(){ do{ var name = prefix + (n++); }while(document.getElementById(name)); return name; }; })(); 18
  • 19. Practical closures II // parameterize a function var scale = function(factor){ return function(x){ return factor * x; }; }; // use var double = scale(2), triple = scale(3); var x = double(21); var y = triple(14); 19
  • 20. this: fine points I • Every function is called in a context of an object or the global scope. • this is a pseudo-variable, which always points to the current context. • It cannot be pulled from a closure. • Contexts are not inherited. 20
  • 21. this: fine points II • Specifying a context implicitly: var name = “global”; var abc = function(a, b, c){ alert(this.name); }; var myObj = {name: “myObj”, method: abc}; // calling method in the context of myObj myObj.method(1, 2, 3); // this === myObj myObj[“method”](1, 2, 3); // this === myObj // calling function in the global context abc(1, 2, 3); // this === global 21
  • 22. this: fine points III • Specifying a context explicitly: var abc = function(a, b, c){ alert(this.name); }; var myObj = {name: “myObj”}; // calling method in the context of myObj abc.apply(myObj, [1, 2, 3]); // this === myObj abc.call(myObj, 1, 2, 3); // this === myObj 22
  • 23. this: fine points IV • Accessing outer this – just reassign this to a regular variable: function f1(){ // this is “this #1” var self = this; function f2(){ // this is “this #2” // generally “this #2” !== “this #1” // but “self” is guaranteed to be “this #1” } 23
  • 24. arguments • Another pseudo-variable with fine points and restrictions similar to this. • It has two cool properties: • “arguments.caller” to specify who calls you function. • “arguments.callee” to specify your function anonymously. 24
  • 25. Hash-based objects I • Everything is an object. Sounds familiar? • All objects are hash-based dictionaries of key-value pairs. • Hash-based the access is constant. • Embedded sub-objects and references can produce arbitrary complex graphs. 25
  • 26. Hash-based objects II • We can add/remove custom properties at will. • Read-only objects: numbers, strings, booleans, null, undefined. • Objects are represented by references. • Read-only objects simulate the “value” semantics. 26
  • 27. OOP Different flavors and approaches. 27
  • 28. OOP: short intro • Object-oriented programming is an important paradigm. • It is a way to organize/partition code into simple objects, which encapsulate state, and associated functionality. • There are many flavors of OOP. • The simplest ones are the most useful. 28
  • 29. OOP: duck-typing I • We can do OOP without classes! • Example: • We have an iterator interface: • next() – returns “next” object. • hasNext() – returns true, if there is “next” object, and false otherwise. 29
  • 30. OOP: duck-typing II • Notable: • The iterator interface here is a concept, it does’t have any corresponding code. • We don’t derive anything from anything. • We don’t even need a class. • We rely on human conventions rather than syntactic/semantic contracts. 30
  • 31. OOP: duck-typing III • Let’s implement a counter from 1 to 5: var it = { value: 1, limit: 5, hasNext: function(){ return this.value <= this.limit; }, next: function(){ return this.value++; } }; // consumer function consume(it){ while(it.hasNext()){ alert(it.next()); } } 31
  • 32. OOP: duck-typing IV • Let’s implement a stack-based iterator: var it = { stack: [1, 2, 3, 4, 5], hasNext: function(){ return this.stack.length; }, next: function(){ return this.stack.pop(); } }; // consumer is exactly the same function consume(it){ while(it.hasNext()){ alert(it.next()); } } 32
  • 33. No constructors? • What if we want to create several similar objects? • We need constructors. • Yes, it is possible to have constructors without classes. 33
  • 34. OOP: factories I • Any function that return an object will do. • Let’s construct our simple iterator: function makeIt(from, to){ return { value: from, limit: to, hasNext: function(){ return this.value <= this.limit; }, next: function(){ return this.value++; } }; } 34
  • 35. OOP: factories II • Closure version of our simple iterator: function makeIt(from, to){ var counter = from; function hasNext(){ return counter <= to; } function next(){ return counter++; } return { hasNext: hasNext, next: next }; } 35
  • 36. OOP: prototypes • JavaScript has notions of constructors and inheritance. • But it doesn’t provide classes per se. • The inheritance is of prototypal nature: • Objects can delegate (statically) some properties to another object, and so on. 36
  • 37. OOP: constructor I • Constructor can be any function. • When it runs its context is set to a newly created object. • Usually it is modified as a part of initialization. • Alternatively a constructor can return a totally different object (rarely used). 37
  • 38. OOP: constructor II • Constructor has one important property: prototype. • It points to a delegatee object. • Usually a constructor is invoked with the new operator. 38
  • 39. OOP: new operator • new creates a proper object (a generic object for user-defined constructors). • It takes a prototype from a constructor object and assigns it to the newly created object (this step cannot be done in any other way). • It passes the object as a context to a constructor. 39
  • 40. OOP: delegate • Now we can write a generic delegate: var delegate = (function(){ function temp(){} // it’ll hold a prototype reference return function(obj){ temp.prototype = obj; // saving a prototype var t = new temp(); // new object is delegated temp.prototype = null; // avoid a memory leak return t; }; })(); 40
  • 41. OOP: using delegate I var a = { hello: function(){ console.log(“Hello!”); }, zen: function(){ console.log(“O-O-OM”); } }; a.hello(); // Hello! var b = delegate(a); b.hello(); // Hello! b.hello = function(){ console.log(“Huh?”); }; a.hello(); // Hello! b.hello(); // Huh? 41
  • 42. OOP: using delegate II var c = delegate(b); a.hello(); // Hello! b.hello(); // Huh? c.hello(); // Huh? c.hello = function(){ console.log(“HI!!!”); }; a.hello(); // Hello! b.hello(); // Huh? c.hello(); // HI!!! delete c.hello; c.hello(); // Huh? 42
  • 43. OOP: advanced I • We just saw how we can organize our code using the single inheritance. • Many JS libraries provide OOP helpers: • An analog of delegate(). • A mix in procedure, which adds properties of one object to another. 43
  • 44. OOP: advanced II • dojo.declare() provides: • Multiple inheritance based on class linearization (using C3 MRO). • Chaining for constructors and regular methods. • Simple inherited() calls to augment an existing functionality. 44
  • 45. OOP: advanced III • This is a big topic, which we can discuss some other time. 45
  • 46. AOP Important aspects. 46
  • 47. AOP: short intro I • Aspect-oriented programming pays attention to cross-cutting concerns implemented as advices, which can be applied to pointcuts. • Pointcuts define “events” in our program where we can insert some extra code. 47
  • 48. AOP: short intro II • Examples of cross-cutting concerns: • Time/profile a function call. • Put all newly constructed objects in a list so we can iterate over them, remove them on destruction. • Cache results of an expensive pure function, and reuse them. 48
  • 49. AOP: short intro III • All examples demonstrate common things: • Code required to perform an advice does not depend on a nature of functions/objects it operates on. • AOP is just another way to structure you code. 49
  • 50. AOP in JavaScript • We can reliably intercept one thing: a method call. • In most cases it is more than enough for practical programmers. • All advice types can be implemented: • before, around, after, afterReturning, afterThrowing. 50
  • 51. AOP: toy example I • Let’s implement the “afterReturning” advice: function attachAfterReturning(obj, name, advice){ var old = obj[name]; obj[name] = function(){ var result = old.apply(this, arguments); advice.call(this, result); return result; }; } 51
  • 52. AOP: toy example II • Let’s implement the “before” advice: function attachBefore(obj, name, advice){ var old = obj[name]; obj[name] = function(){ advice. apply(this, arguments); return old.apply(this, arguments); }; } 52
  • 53. AOP: toy example III • Let’s implement the “around” advice: function attachAround(obj, name, advice){ var old = obj[name]; obj[name] = function(){ return advice.call(this, arguments, old); }; } 53
  • 54. AOP: advice example I • Simple tracer as “around” advice: var tracer = (function(){ var stack = []; return function(args, old){ console.log(“=> start”); stack.push(new Date().getTime()); var result = old.apply(this, args); var ms = new Date().getTime() - stack.pop(); console.log(“<= finish: “ + ms); return result; }; })(); 54
  • 55. AOP: using tracer var fact = { fact: function(n){ return n < 2 ? 1 : n * this.fact(n); } }; attachAround(fact, “fact”, tracer); fact.fact(3); // prints: // => start // => start // => start // <= finish: XX // <= finish: YY // <= finish: ZZ 55
  • 56. AOP: advice example II • Simple 1-arg memoization as two advices: var memoizer = function(){ var cache = {}; var memoizer = function(args, old){ var arg = args[0]; if(arg in cache){ return cache[arg]; } return cache[arg] = old.call(this, arg); }; memoizer.clear = function(){ cache = {}; }; return memoizer; }; 56
  • 57. AOP: using memoizer var fact = { fact: function(n){ return n < 2 ? 1 : n * this.fact(n); } }; var mem = memoizer(); attachAround(fact, “fact”, mem); console.log(fact.fact(55)); // repeated calculations will be very fast: console.log(fact.fact(60)); // “forget” previously calculated values mem.clear(); 57
  • 58. AOP and OOP I • There are some parallels between AOP and OOP: • Method chaining can be imagined as advices: • Constructors are chained using “after” advices. • Destructors are chained using “before”. 58
  • 59. AOP and OOP II • Super calls (inherited() calls) can be represented as “around” advice. • These similarities are not by chance. They reflect fundamental properties of OOP expressed in AOP terms. 59
  • 60. More on AOP • I wrote a blog post about AOP in JS and how it is implemented in Dojo: • http://lazutkin.com/blog/2008/may/18/ aop-aspect-javascript-dojo/ 60
  • 61. Intermediate stop • …and I ran out of time. • Next month we will talk about: • Functional programming (FP). • Domain-specific languages (DSL). • How JavaScript supports code generation (CG) techniques. 61
  • 62. About me • I am an independent software developer. • My web site: • http://lazutkin.com • Follow me on Tweeter: • http://twitter.com/uhop 62