Exciting JavaScript What makes it unique, how to use it. Eugene Lazutkin Dallas, TX, ClubAjax on 3/2/2010 1
Disclaimer • I will use JavaScript, JS, and ECMAScript interchangeably. • The material is mostly based on ECMAScript 3. 2
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
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
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
What we did last time • We look into the JavaScript-specific language facilities to see what it offers. • We dissected OOP and AOP paradigms. • We mapped simple OOP and AOP paradigms on top of available constructs. 6
What we found • 1st-class functions. • Closures. • Hash-based extendable objects. • Duck-typing rules! • OOP can be made with a language, rather than provided by a language. 7
Simple OOP // our constructor var Person = function(name){ // our instance-level variables this.name = name; }; // our methods and class-level variables/constants Person.prototype = { answer: 42, say: function(msg){ alert(this.name + “: “ + msg); } }; 8
Simple AOP // augmenting Person’s say() var old = Person.prototype.say; Person.prototype.say = function(msg){ var newMsg = msg.toUpperCase(); old.call(this, newMsg); }; // WARNING: this augmentation doesn’t scale up // well, use something like dojox.lang.aop 9
FP Functional approach. 10
FP: short intro I • It is about representing algorithms as a composition of functions. • It stresses out the algorithmic part of programming. • It is not about states (unlike OOP), but about a control flow. 11
FP: short intro II • Higher-order functions: • Can consume other functions as parameters. • Can return functions. • That’s where “function as a 1st-order value” pays off. 12
FP: short intro III • Pure functions: • No side-effects. • Why? Easier to combine. • Recursion is important: • We can do it JS too. 13
FP in JavaScript? • Some pieces of our program can be functional (e.g., stateless). • Some side-effects can be deemed “harmless for our purposes”. • They do not affect our algorithm. 14
FP in JavaScript • Practical FP in JS: • Use adapters to customize components. • Combine components using chaining. • Convert flow statements into functions. • While jQuery is not an FP toolkit, it has popularized the style. 15
FP: adapter example • Remember our hack with “self = this”? We can adapt our functions/methods for that: function hitch(obj, name){ return function(){ var fn = typeof name == “string” ? obj[name] : name; return fn.apply(obj, arguments); }; } 16
FP: using hitch var queue = { stack: [], memorize: function(x){ this.stack.push(x); } }; queue.memorize(2); // or we can use it as a function with any context var q = hitch(queue, “memorize”); q(2); q(3); 17
FP: control flow • Control flow can be implemented as higher-order functions. • Traditionally iteration and recursion are major sources of programmer’s errors. • Cut’n’paste frequently breaks internal loop variables. 18
FP: “array extras” • Back in Firefox 1.5 so-called “array extras” were introduced: • forEach(), every(), some(), map(), filter(), indexOf(), lastIndexOf(). • Firefox 3 added: reduce(), reduceRight(). • They allow to process arrays as streams eliminating direct loops. 19
FP: process arrays • “Array extras” allows writing very compact neatly piped data processing: var data = [...]; var result = data. map(function(x){ return x * x; }). filter(function(x){ return x % 2 == 1; }). reduce(function(a, b){ return a + b; }); 20
More on FP • jQuery uses similar techniques on NodeList with great success. • I wrote a blog post about FP in JS and how it is implemented in Dojo: • http://lazutkin.com/blog/2008/jan/12/ functional-fun-javascript-dojo/ 21
Inventory (cont.) Dynamic language. 22
Code generation I • JavaScript can compile text to an executable code with two constructs: • eval() – compile a string as JavaScript. Any valid JavaScript can be compiled. • new Function() – compile a function. • We can generate code for fun and profit! 23
Code generation II • Some environments do not allow code generation. • Sandboxes can prohibit it for security reasons. • ES5 strict mode doesn’t allow it. It works in ES5 strict mode with some caveats. • All browsers in normal mode support it. 24
Introspection I • “for-in” loop enumerates all keys in an object. • Some keys can be hidden. • Function.toString() can return a source code for a function. • Some implementations (e.g., mobile) do not support this feature. 25
Introspection II • Function has some additional properties like “name” or “length”. • Some browsers do not support them. • ES5 strict mode doesn’t allow inspection of “arguments.caller” and “arguments.callee”. 26
CG advantage • Having CG around opens new vistas: • We can generate code custom-tailored (optimized) to a specific task completely on the fly. • We can use Domain-Specific Languages (DSL) to simplify our problems at hand. 27
DSL Domain-specific languages and code generation. 28
Implementing DSL I • DSL can be implemented in several layers: • By providing objects and libraries specific for our problem area. • Example: HTML DOM. • Example: CSS. • Example: JSON. 29
Implementing DSL II • If our language supports it, we can provide special language constructs to make our tasks simpler: • Example: regular expressions in JavaScript. • Example: NodeList and jQuery, or dojo.query, or similar facilities of other libraries for HTML DOM and CSS. 30
Implementing DSL III • Finally we can implement our own custom language, and interpret it, or compile it to our implementation language. • Trade-offs are easy to assess: cost of abstraction (e.g., compile time) vs. run time. 31
HTML as DSL // let’s “program” a list var list = “ <ul> <li>Mike</li> <li>Bob</li> </ul>”; // let’s “interpret” it ourDomNode.innerHTML = list; // let’s read it back var text = ourDomNode.innerHTML; 32
CSS as DSL // CSS selector is used in dojo.query // (all major libraries can do that nowadays) dojo.query(“.myClass li”). style({ color: “blue”, background: “yellow” }); 33
JSON as DSL // Let’s produce some JSON var str = JSON.stringify({ answer: 42, array: [1, 2, 3, 4], subObject: {name: “Mike”} }); // old-school JSON “interpretation” // (WARNING: don’t do it at home!) var obj = eval(“(“ + str + ”)”); 34
DSL: lambdas I • Our functional example (slide 20) was as compact as possible in JavaScript. But imagine that we had a way to reduce the functions we used? • We could have something like that: var result = data.map(“x * x”).filter(“x % 2 == 1”).reduce(“+”); 35
DSL: lambdas II • Oliver Steele came up with a simple set of rules for such language: • If lambda ends with an operator, it is a place for an implicit argument: • “2+” function(x){ return 2 + x; } 36
DSL: lambdas III • If lambda starts with an operator, it is a place for an implicit argument: • “+2” function(x){ return x + 2; } • “+” function(x, y){ return x + y; } • “/2+” function(x, y){ return x / 2 + y; } 37
DSL: lambdas IV • If lambda contains “->” it means it is a full- blown function: • “a, b -> a + b” • function(a, b){ return a + b; } • “a, b -> Math.min(a, b)” • function(a, b){ return Math.min(a, b); } 38
DSL: lambdas V • Otherwise all different identifiers in a string starting with a lower-case symbol assumed to be arguments: • “x + y” function(x, y){ return x + y; } • Obviously all reserved words (like “this”) are not considered to be arguments. 39
DSL: lambdas VI • dojox.lang.functional implements Oliver’s lambda specification. • They can be used consistently in any functions provided by this package. • Special compilation helpers are provided. 40
DSL: using lambdas I • lambda() is a function to convert from lambda strings to functions. • Let’s rewrite our example: var result = data.map(lambda(“x * x”)). filter(lambda(“x % 2 == 1”)). reduce(lambda(“+”)); 41
DSL: using lambdas II • Better, but not an ideal. • Let’s implement functions, which can take either a function or a lambda string: var forEach = function(a, f){ return a.forEach(typeof f == “string” ? lambda(f): f); }; // and so on for other functions 42
DSL: using lambdas III • Now we can reimplement the example: var result = map(data, “x * x”); result = filter(result, “x % 2 == 1”); result = reduce(result, “+”); • I would say it is much better, yet chaining would be a better solution. • You can do it as an exercise. 43
DSL: results I • While our code is more compact and more readable, it takes a hit to compile a lambda. • While the hit is relatively small, we can amortize it by pre-calculating a lambda: var f = lambda(“x * x”); var result = map(data, f); 44
DSL: results II • Lambdas are harder to debug because we don’t have a direct correspondence with the code. • We can mitigate it by using small concise expressions. (That’s the idea anyway). 45
Conclusion • JavaScript has a lot of potential from the language point of view. • We just opening it up for real large scale development. • Over time we will see more and more non- browser JavaScript-based projects, and more complex browser-based apps. 46
About me • I am an independent software developer. • My web site: • http://lazutkin.com • Follow me on Tweeter: • http://twitter.com/uhop 47

Exciting JavaScript - Part II

  • 1.
    Exciting JavaScript Whatmakes it unique, how to use it. Eugene Lazutkin Dallas, TX, ClubAjax on 3/2/2010 1
  • 2.
    Disclaimer • I willuse 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 LanguageI • 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 LanguageII • Following paradigms can be supported: • Object-oriented programming (OOP). • Functional programming (FP). • Aspect-oriented programming (AOP). • Event-driven programming (EDP). • Much more. 5
  • 6.
    What we didlast time • We look into the JavaScript-specific language facilities to see what it offers. • We dissected OOP and AOP paradigms. • We mapped simple OOP and AOP paradigms on top of available constructs. 6
  • 7.
    What we found •1st-class functions. • Closures. • Hash-based extendable objects. • Duck-typing rules! • OOP can be made with a language, rather than provided by a language. 7
  • 8.
    Simple OOP // ourconstructor var Person = function(name){ // our instance-level variables this.name = name; }; // our methods and class-level variables/constants Person.prototype = { answer: 42, say: function(msg){ alert(this.name + “: “ + msg); } }; 8
  • 9.
    Simple AOP // augmentingPerson’s say() var old = Person.prototype.say; Person.prototype.say = function(msg){ var newMsg = msg.toUpperCase(); old.call(this, newMsg); }; // WARNING: this augmentation doesn’t scale up // well, use something like dojox.lang.aop 9
  • 10.
  • 11.
    FP: short introI • It is about representing algorithms as a composition of functions. • It stresses out the algorithmic part of programming. • It is not about states (unlike OOP), but about a control flow. 11
  • 12.
    FP: short introII • Higher-order functions: • Can consume other functions as parameters. • Can return functions. • That’s where “function as a 1st-order value” pays off. 12
  • 13.
    FP: short introIII • Pure functions: • No side-effects. • Why? Easier to combine. • Recursion is important: • We can do it JS too. 13
  • 14.
    FP in JavaScript? •Some pieces of our program can be functional (e.g., stateless). • Some side-effects can be deemed “harmless for our purposes”. • They do not affect our algorithm. 14
  • 15.
    FP in JavaScript •Practical FP in JS: • Use adapters to customize components. • Combine components using chaining. • Convert flow statements into functions. • While jQuery is not an FP toolkit, it has popularized the style. 15
  • 16.
    FP: adapter example •Remember our hack with “self = this”? We can adapt our functions/methods for that: function hitch(obj, name){ return function(){ var fn = typeof name == “string” ? obj[name] : name; return fn.apply(obj, arguments); }; } 16
  • 17.
    FP: using hitch varqueue = { stack: [], memorize: function(x){ this.stack.push(x); } }; queue.memorize(2); // or we can use it as a function with any context var q = hitch(queue, “memorize”); q(2); q(3); 17
  • 18.
    FP: control flow •Control flow can be implemented as higher-order functions. • Traditionally iteration and recursion are major sources of programmer’s errors. • Cut’n’paste frequently breaks internal loop variables. 18
  • 19.
    FP: “array extras” •Back in Firefox 1.5 so-called “array extras” were introduced: • forEach(), every(), some(), map(), filter(), indexOf(), lastIndexOf(). • Firefox 3 added: reduce(), reduceRight(). • They allow to process arrays as streams eliminating direct loops. 19
  • 20.
    FP: process arrays •“Array extras” allows writing very compact neatly piped data processing: var data = [...]; var result = data. map(function(x){ return x * x; }). filter(function(x){ return x % 2 == 1; }). reduce(function(a, b){ return a + b; }); 20
  • 21.
    More on FP •jQuery uses similar techniques on NodeList with great success. • I wrote a blog post about FP in JS and how it is implemented in Dojo: • http://lazutkin.com/blog/2008/jan/12/ functional-fun-javascript-dojo/ 21
  • 22.
    Inventory (cont.) Dynamic language. 22
  • 23.
    Code generation I •JavaScript can compile text to an executable code with two constructs: • eval() – compile a string as JavaScript. Any valid JavaScript can be compiled. • new Function() – compile a function. • We can generate code for fun and profit! 23
  • 24.
    Code generation II •Some environments do not allow code generation. • Sandboxes can prohibit it for security reasons. • ES5 strict mode doesn’t allow it. It works in ES5 strict mode with some caveats. • All browsers in normal mode support it. 24
  • 25.
    Introspection I • “for-in”loop enumerates all keys in an object. • Some keys can be hidden. • Function.toString() can return a source code for a function. • Some implementations (e.g., mobile) do not support this feature. 25
  • 26.
    Introspection II • Functionhas some additional properties like “name” or “length”. • Some browsers do not support them. • ES5 strict mode doesn’t allow inspection of “arguments.caller” and “arguments.callee”. 26
  • 27.
    CG advantage • HavingCG around opens new vistas: • We can generate code custom-tailored (optimized) to a specific task completely on the fly. • We can use Domain-Specific Languages (DSL) to simplify our problems at hand. 27
  • 28.
  • 29.
    Implementing DSL I •DSL can be implemented in several layers: • By providing objects and libraries specific for our problem area. • Example: HTML DOM. • Example: CSS. • Example: JSON. 29
  • 30.
    Implementing DSL II •If our language supports it, we can provide special language constructs to make our tasks simpler: • Example: regular expressions in JavaScript. • Example: NodeList and jQuery, or dojo.query, or similar facilities of other libraries for HTML DOM and CSS. 30
  • 31.
    Implementing DSL III •Finally we can implement our own custom language, and interpret it, or compile it to our implementation language. • Trade-offs are easy to assess: cost of abstraction (e.g., compile time) vs. run time. 31
  • 32.
    HTML as DSL //let’s “program” a list var list = “ <ul> <li>Mike</li> <li>Bob</li> </ul>”; // let’s “interpret” it ourDomNode.innerHTML = list; // let’s read it back var text = ourDomNode.innerHTML; 32
  • 33.
    CSS as DSL //CSS selector is used in dojo.query // (all major libraries can do that nowadays) dojo.query(“.myClass li”). style({ color: “blue”, background: “yellow” }); 33
  • 34.
    JSON as DSL //Let’s produce some JSON var str = JSON.stringify({ answer: 42, array: [1, 2, 3, 4], subObject: {name: “Mike”} }); // old-school JSON “interpretation” // (WARNING: don’t do it at home!) var obj = eval(“(“ + str + ”)”); 34
  • 35.
    DSL: lambdas I •Our functional example (slide 20) was as compact as possible in JavaScript. But imagine that we had a way to reduce the functions we used? • We could have something like that: var result = data.map(“x * x”).filter(“x % 2 == 1”).reduce(“+”); 35
  • 36.
    DSL: lambdas II •Oliver Steele came up with a simple set of rules for such language: • If lambda ends with an operator, it is a place for an implicit argument: • “2+” function(x){ return 2 + x; } 36
  • 37.
    DSL: lambdas III •If lambda starts with an operator, it is a place for an implicit argument: • “+2” function(x){ return x + 2; } • “+” function(x, y){ return x + y; } • “/2+” function(x, y){ return x / 2 + y; } 37
  • 38.
    DSL: lambdas IV •If lambda contains “->” it means it is a full- blown function: • “a, b -> a + b” • function(a, b){ return a + b; } • “a, b -> Math.min(a, b)” • function(a, b){ return Math.min(a, b); } 38
  • 39.
    DSL: lambdas V •Otherwise all different identifiers in a string starting with a lower-case symbol assumed to be arguments: • “x + y” function(x, y){ return x + y; } • Obviously all reserved words (like “this”) are not considered to be arguments. 39
  • 40.
    DSL: lambdas VI •dojox.lang.functional implements Oliver’s lambda specification. • They can be used consistently in any functions provided by this package. • Special compilation helpers are provided. 40
  • 41.
    DSL: using lambdasI • lambda() is a function to convert from lambda strings to functions. • Let’s rewrite our example: var result = data.map(lambda(“x * x”)). filter(lambda(“x % 2 == 1”)). reduce(lambda(“+”)); 41
  • 42.
    DSL: using lambdasII • Better, but not an ideal. • Let’s implement functions, which can take either a function or a lambda string: var forEach = function(a, f){ return a.forEach(typeof f == “string” ? lambda(f): f); }; // and so on for other functions 42
  • 43.
    DSL: using lambdasIII • Now we can reimplement the example: var result = map(data, “x * x”); result = filter(result, “x % 2 == 1”); result = reduce(result, “+”); • I would say it is much better, yet chaining would be a better solution. • You can do it as an exercise. 43
  • 44.
    DSL: results I •While our code is more compact and more readable, it takes a hit to compile a lambda. • While the hit is relatively small, we can amortize it by pre-calculating a lambda: var f = lambda(“x * x”); var result = map(data, f); 44
  • 45.
    DSL: results II •Lambdas are harder to debug because we don’t have a direct correspondence with the code. • We can mitigate it by using small concise expressions. (That’s the idea anyway). 45
  • 46.
    Conclusion • JavaScript hasa lot of potential from the language point of view. • We just opening it up for real large scale development. • Over time we will see more and more non- browser JavaScript-based projects, and more complex browser-based apps. 46
  • 47.
    About me • Iam an independent software developer. • My web site: • http://lazutkin.com • Follow me on Tweeter: • http://twitter.com/uhop 47