This document discusses exciting features of JavaScript including how it can be used in browsers and non-browser environments. It covers how JavaScript supports object-oriented, functional, and aspect-oriented programming paradigms through its first-class functions, closures, and other language features. The document also discusses how code generation and introspection are possible in JavaScript and how this enables implementing domain-specific languages through techniques like lambda functions. In conclusion, the author expresses optimism about JavaScript's potential for large-scale development.
Scaling API-first – The story of a global engineering organization
JavaScript's Unique Features and How to Use Them
1. Exciting JavaScript
What makes it unique, how to use it.
Eugene Lazutkin
Dallas, TX, ClubAjax on 3/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. 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
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
9. 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
11. 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
12. 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
13. FP: short intro III
• 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
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
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
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
• 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
27. 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
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 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
42. 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
43. 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
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 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
47. About me
• I am an independent software developer.
• My web site:
• http://lazutkin.com
• Follow me on Tweeter:
• http://twitter.com/uhop
47