How we Learned to Stop Worrying and Love JavaScript

How we Learned to Stop Worrying and Love JavaScript

Presented at Fluent Conference, San Francisco May 31st 2012

52c6174ba60557536f93809b4e95d97c?s=128

Angus Croll

May 31, 2012
Tweet

Transcript

  1. How We Learned To Stop Worrying And Love JavaScript @danwrong

    @angustweets
  2. We’ve been busy...

  3. None
  4. Rethinking twitter.com ‣ Use the right tool for the job.

    Don’t JavaScript all the things. ‣ Take advantage of the browser and of the nature of JavaScript rather than fighting it.
  5. None
  6. Reuse patterns that make use of JavaScript rather than fight

    it
  7. The hardest part...

  8. The hardest part...

  9. The hardest part...

  10. So, talking animals it is... meow!!

  11. Prototypes ‣ JavaScript’s Agent of Re-use ‣ Flexible but Awkward

    ‣ new <constructor> syntax encourages classical model ‣ Prototype chains are single rooted ‣ Inheritance syntax is gnarly
  12. var Animal = function(gender, says) { this.gender = gender; this.says

    = says; }; var WalkingAnimal = function(gender, says) { Animal.call(this, gender, says); } WalkingAnimal.prototype = new Animal(); // http://jsfiddle.net/96BSq/
  13. var Animal = function(gender, says) { this.gender = gender; this.says

    = says; }; var WalkingAnimal = function(gender, says) { Animal.call(this, gender, says); } WalkingAnimal.prototype = new Animal(); // http://jsfiddle.net/96BSq/
  14. Class syntax ‣ JS native class syntax scheduled for ES6

    ‣ class, extend and super are reserved words ‣ Library implementation varies widely and abstraction is often leaky (‘const’, ‘static’) ‣ In particular, the relationship between this and super is difficult
  15. //Prototype.js var SwimmingAnimal = Class.create(Animal, { type: 'SwimmingAnimal', speak: function($super)

    { return $super() + ", glug"; } }); //Dustin Diaz's "klass" var Alien = SuperHuman.extend({ beem: function() { this.supr(); // beem into space } });
  16. //Prototype.js var SwimmingAnimal = Class.create(Animal, { type: 'SwimmingAnimal', speak: function($super)

    { return $super() + ", glug"; } }); //Dustin Diaz's "klass" var Alien = SuperHuman.extend({ beem: function() { this.supr(); // beem into space } });
  17. //Prototype.js var SwimmingAnimal = Class.create(Animal, { type: 'SwimmingAnimal', speak: function($super)

    { return $super() + ", glug"; } }); //Dustin Diaz's "klass" var Alien = SuperHuman.extend({ beem: function() { this.supr(); // beem into space } });
  18. Class hierarchies

  19. Class hierarchies WTF? I walk too!

  20. Class hierarchies Duck? WTF? I walk too!

  21. Class hierarchies Duck? WTF? I walk too!

  22. Classical inheritance ‣ Requires up-front knowledge of general case ‣

    Single rooted hierarchy ‣ Types are often too generalized to map to real life coding problems (some animals swim AND walk)
  23. Beyond classification ‣ 19th century British philosophers Whewell and Jevons

    argued that there are no objectively “right” classifications ‣ “In general, when working with prototypes, one typically chooses not to categorize but to exploit alikeness.” Antero Taivalsaari (Nokia Research Center) - Journal of Object Oriented Programming Nov/Dec 1997
  24. Mixins ‣ JavaScript has first class functions ‣ Any property

    can be assigned to any object
  25. //A property copy mixin var withWalking = { walk: function()

    { console.log('walking'); }, turn: function(direction) { console.log('turning', direction); }, stopWalking: function() { console.log('stopped walking'); } };
  26. var extend = function(destination, source) { for (var k in

    source) { if (source.hasOwnProperty(k)) { destination[k] = source[k]; } } return destination; }; extend(Crocodile.prototype, withWalking); extend(Crocodile.prototype, withSwimming); //http://jsfiddle.net/29tW5/
  27. Property copy mixins ‣ No hierarchical constraints ‣ Functionality is

    grouped by what it does not who it belongs to ‣ BUT... ‣ Mixin has no reference to target properties ‣ Properties can only clobber ‣ Target object requires intimate knowledge of mixin properties
  28. Functional mixins ‣ Mixins are functions that assign properties to

    the ‘this’ object. ‣ Mixins are directly invoked in the context of the target object by means of call/apply
  29. var withWalking = function() { this.walk = function() { console.log('walking');

    }; this.turn = function(direction) { console.log('turning', direction); }; this.stopWalking = function() { console.log('stopped walking'); }; }; //http://jsfiddle.net/uyZZL/13/
  30. function Crocodile(name, gender) { this.name = name; this.gender = gender;

    }; Crocodile.prototype.stalkTourists = function() { //.. }; withWalking.call(Crocodile.prototype); withSwimming.call(Crocodile.prototype);
  31. Advice: before, after and around ‣ A mixin that adds,

    underscore.js style, before(), after() and around() to an object. ‣ Other mixins can use this to augment existing methods.
  32. withAdvice.call(Crocodile.prototype); function withFlu() { this.before(“walk”, function() { console.log('sniff'); }) }

    var sickCrocodile = new Crocodile(); withFlu.call(sickCrocodile); sickCrocodile.walk(); //"sniff, pad, pad, pad, pad"
  33. function withCharacterCounter() { this.updateCounter = function() { //... }; //add

    advice after core initialize method this.after('initialize', function() { this.$counter = this.select('counter'); this.on('uiTextUpdated', this.updateCounter); }); }
  34. Functional mixins ‣ Mixins as verbs instead of nouns. ‣

    Mixins are functions. We can take advantage of closure scope, arguments and context. ‣ A mixin can be applied to any object type: prototype, instance, whatever. ‣ Advice allows functional mixins to augment existing functions, not clobber them. ‣ Works with the language, simple to understand, no surprises. Debuggable.
  35. Putting it to work...

  36. function Storage() { this.initialize.call(this, arguments); } function baseStorage() { this.initialize

    = function(namespace) { this.namespace = namespace } this.encode = function(item) { return JSON.stringify(item) } this.decode = function(item) { return JSON.parse(item) } if (window.localStorage) { localStorageEngine.call(this); return; } if (document.documentElement.addBehavior) { userDataEngine.call(this); return; } memoryStorageEngine.call(this); } withAdvice.call(Storage.prototype); baseStorage.call(Storage.prototype);
  37. function localStorageEngine() { this.getItem = function(key) { return this.decode(localStorage.getItem(this.namespace +

    key)); } this.setItem = function(key, val) { return localStorage.setItem(this.namespace + key, this.encode(val)); } }
  38. function memoryStorageEngine() { var store = {}; this.after('initialize', function() {

    this.store = store[this.namespace] = store[this.namespace] || {}; }); this.getItem = function(key) { return this.decode(this.store[this.namespace + key]); } this.setItem = function(key, val) { return this.store[this.namespace + key] = this.encode(val); } }
  39. function withEncryption() { this.after('initialize', function(namespace, secret) { this.secret = secret;

    }); this.around('decode', function(decode, val) { return decode(aes.dec(val, this.secret)); }) this.around('encode', function(encode, val) { return aes.enc(encode(val), this.secret); }); } var encryptedStorage = new Storage('secretStuff'); withEncryption.call(encryptedStorage);
  40. Overview ‣ Functional mixins and advice/AOP are the shit ‣

    Make use of JavaScript’s biggest strength - functions ‣ Extremely simple ‣ Endless flexibility ‣ Drop your class implementations and use this stuff now
  41. Questions?

  42. @jointheflock Visit the booth and chat to us twitter.com/jobs Happy

    hour tonight Beer.js!