Advanced JavaScript

535 views

Published on

Some advanced topics, functinal approach, popular OO inheritance patterns.

0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
535
On SlideShare
0
From Embeds
0
Number of Embeds
8
Actions
Shares
0
Downloads
11
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Advanced JavaScript

  1. 1. Language philosophy, advanced featuresADVANCED JAVASCRIPT Zsolt Mészárovics <EPAM>
  2. 2. $ whoamiProgramming languages: Compiled, general purpose: Java; C/C++; Scala Scripting: JavaScript; Python; etc… Experimental: Go; Dart; CoffeeScriptRecent works (non-project, related to JS): NodeJS based stuff involving custom C++ extensions Closure Compiler / Closure Templates enhancements
  3. 3. Agenda OO Inheritance patterns in JS, which one to use? Exploiting functional paradigm support Asynchronity in JS (still) common pitfalls, how to avoid them? Agenda is based on my observations during every day work, working with 3rd party sources.
  4. 4. OO & Inheritance Patterns Devs tend to trust various frameworks to construct classes with inheritance.Popular types (Crockford’s terms): „Pseudoclassical” „Power-constructor” or „Parasital”Trends: Avoiding new keyword Emulating private members with closures Assembling objects from prototypes „by hand”
  5. 5. Pseudo-Classical PatternPopular types (Crockfod’s terms): „Pseudo-classical” „Power-Constructor” or „Parasital”Concerning trends: „Power constructors” – avoiding new keyword Emulating private members with closures Assembling objects from prototypes „by hand”
  6. 6. Pseudo-Classical Example function Shape(x, y) { this.x = x; this.y = y; } Shape.prototype.move = function (x, y) { this.x += x; this.y += y; }; function Rectangle(x1, y1, x2, y2) { Shape.call(this, (x1 + x2) / 2, (y1 + y2) / 2); this.x1 = x1; this.x2 = x2; this.y1 = y1; this.y2 = y2; } Rectangle.prototype = Object.create(Shape.prototype); // may poly Rectangle.prototype.area = function () { return (this.x2 - this.x1) * (this.y2 - this.y1); };
  7. 7. Object.create Polyfill if (!Object.create) { Object.create = function (o) { if (arguments.length > 1) { throw new Error(properties not implemented); } function F() {} F.prototype = o; return new F(); }; }
  8. 8. Power-Constructor Example function Shape(x, y) { return { x: x, y: y, move: function (x, y) { this.x += x; this.y += y; } }; } function Rectangle(x1, y1, x2, y2) { var self = Shape((x1 + x2) / 2, (y1 + y2) / 2); self.x1 = x1; self.x2 = x2; self.y1 = y1; self.y2 = y2; self.area = function () { return (self.x2 - self.x1) * (self.y2 - this.y1); }; return self; }
  9. 9. Difference of Resulting ObjectsPrototype chain (__proto__): „Pseudo-Classical” „Power-constructor” Rectangle Rectangle + Shape Shape Object Object Shape Object • layered structure, head object • flat structure, every head has only instance members object has all members • Instantiated with new • new keyword is optional keyword
  10. 10. Which One is Better? Power-Constructor pattern is extremely popular. A lot of frameworks using it, including jQuery. Do we need privates? – not really Performance?Demo time! Let’s evaluate performance with a particle system.
  11. 11. ConclusionDespite a little bit more verbose, might look not as self-contained thanother variants, Pseudo-Classical inheritance is the way to go.Advantages: Way batter performance, especially at large number of instances Better IDE recognition Better tooling (Closure-Compiler friendly)
  12. 12. Functional Paradigm: Higher Order FunctionsFunctions could be passed as arguments, and could be returned by otherfunctions as return values.Functions are threated as first-class values.This provides a flexible way to compose programs.
  13. 13. Example:Take the sum of the integers between a and b: // sum of integers between a and b function sumInts(a, b) { var sum = 0, i; for (i = a; i <= b; i += 1) { sum += i; } return sum; }Take the sum of the cubes of all integers between a and b: function cube(n) { return Math.pow(n, 3); } function sumCubes(a, b) { var sum = 0, i; for (i = a; i <= b; i += 1) { sum += cube(i); } return sum; }
  14. 14. Example (continued) function factorial(n) { var i, f = 1; for (i = 2; i <= n; i += 1) { f *= i; } return f; } function sumFactorials(a, b) { var sum = 0, i; for (i = a; i <= b; i += 1) { sum += factorial(i); } return sum; }
  15. 15. Advanced version using higher-order functionsA generic sum: function sum(f, a, b) { var sum = 0, i; for (i = a; i <= b; i += 1) { sum += f(i); } return sum; }Rewritten special cases: function identity(n) { return n; } sumInts = function (a, b) { return sum(identity, a, b); }; sumCubes = function (a, b) { return sum(cube, a, b); }; sumFactorials = function (a, b) { return sum(factorial, a, b); };Taking functions as parameters, but still a lot of redundancy here…
  16. 16. More advanced version, removed redundancyLet’s rewrite sum to return a function: function sum(fn) { return function (a, b) { var sum = 0, i; for (i = a; i <= b; i += 1) { sum += fn(i); } return sum; }; }So specific cases could be written as: sumInts = sum(identity); sumCubes = sum(cube); sumFactorials = sum(factorial);Or could be invoked without the middle-man: // equivalent to sumCubes sum(cube)(3, 5); // sum of the halves of integers between a and b sum(function (n) { return Math.round(n / 2); })(3, 5);
  17. 17. AsynchronicityJS is… Event driven Single threaded (setTimeout doesn’t do the trick)  Long running code could block execution, UI responsiveness Standard APIs rely on call-backs  They are often nested multiple levels  Hard to debug: reading the call-stack is hard; exceptions might not get propagated up to the initiator  „Pyramid of Doom”!
  18. 18. Difficulties with Call-backs„Pyramid of doom”When the code marches to the right faster than it marches forward: step1(function (value1) { step2(value1, function(value2) { step3(value2, function(value3) { step4(value3, function(value4) { // Do something with value4 }); }); }); });This is sequential, what if step3 could be executed when both step1 andstep2 are completed, but those two steps doesn’t depend on each other?
  19. 19. Difficulties with Call-backs (continued)Synchronizing multiple call-backs var callbackACompleted = false; var callbackBCompleted = false; function callbackA(result) { // process result callbackACompleted = true; if (callbackBCompleted) { done(); } } function callbackB(result) { // process result callbackBCompleted = true; if (callbackACompleted) { done(); } } function done() { // things to do when boot callbacks completed their jobs } processA(params, callbackA); processB(params, callbackB);
  20. 20. Deferred objects / Promises / Futures Designed to solve exactly these problems Under used, not widely knownAPI done() then() A promise is the stripped down Promise version of the deferred instance, fail() Deferred doesn’t contain any state mutator always() methods. resolve() reject()Usage: a task creates a deferred object, and resolves (or fails it) later bycalling .resolve() / .reject(). Clients use promise, which doesn’t provide statemanipulation, just change subscription methods.
  21. 21. Demo
  22. 22. PitfallsArray Deleting delete arr[2]; // [1, 3, undefined × 1, 29, 45, 51] arr.splice(2, 1); // ok! [1, 3, 29, 45, 51] Never attempt to remove an element from an array with delete, use splice. Sorting arr = [1, 3, 24, 29, 45, 51]; arr.sort(); // [1, 24, 29, 3, 45, 51] arr.sort(function (x, y) {return x > y;}); // ok What happened? Don’t relay on default sort functionality; implement getComparator() -> function for objects.
  23. 23. Pitfalls (continued)Number Conversion +"08"; // ok (8) +new Date; // .valueOF() Number("08"); // same as + parseInt("08"); // 0 why? parseInt("ff", 16); // 256 Prefer the + unary operator, you may implement valueOf(), always provide radix for parseInt()!Typeof // typeof typeof array === "object"; // Array.isArray() (polyfill) typeof null === "object"; // spec error :( Worst is typeof null, it returns „object” as a result of an early language specification.

×