Slide 1

Slide 1 text

Bringing classical OOP into JavaScript By Dmitry Sheiko

Slide 2

Slide 2 text

Who's the dude? I'm Dmitry Sheiko, a web developer, blogger, open source contributor. http://dsheiko.com @sheiko https://github.com/dsheiko

Slide 3

Slide 3 text

Eager to be a better coder? Reading helps…

Slide 4

Slide 4 text

Reflecting learnt patterns on JavaScript What the hell?! Where are all the classes, interfaces, members visibility, namespaces, mixins?!

Slide 5

Slide 5 text

JavaScript is a class-free language “JavaScript: The World's Most Misunderstood Programming Language”

Slide 6

Slide 6 text

Yet JavaScript is incredibly expressive “The expressiveness of JavaScript provides an enormous amount of power. Even though the language lacks certain useful built-in features, its flexibility allows you to add them yourself…” Ross Harmes, Dustin Diaz. Pro JavaScript Design Patterns

Slide 7

Slide 7 text

Make of JavaScript the language you need As a class-based OOP programmer I would bring to JavaScript following : • classes with private/public members • classical inheritance (abstract class -> class -> .. -> final class) • interfaces • mixins (traits) • type hinting • entry point validators

Slide 8

Slide 8 text

What look like objects in JavaScript Somehow clumsy, isn’t it? var o, SuperTypeConstruct = function() {}, ConstructorFunc = function() { var _privateMember = "private member"; this.publicMember = "public member"; this.privilegedMethod = function() { return _privateMember; } } ConstructorFunc.prototype = new ConstructorFunc(); o = new ConstructorFunc();

Slide 9

Slide 9 text

What I want it to look like var ConcreteClass = function() { // Constructor's job var _privateMember = "private member"; return { __extends__: AbstractClass, __implements__: [Countable, Traversable], __mixin__: [Trait], publicMember: "public member", privilegedMethod: function() { return _privateMember; } } }

Slide 10

Slide 10 text

Can it inherit? With a factory it can: createInstance = function( constr, args, props ) { var instance, members = ( typeof constr === "function" ? constr.apply( constr.prototype, args || [] ) : constr ), Fn = function () {}; xObject.mixin( members || {}, props || {} ); // Inherit from a super type if any specified in __extends__ property if ( members.hasOwnProperty( "__extends__" ) && members.__extends__ ) { constr.prototype = createInstance( members.__extends__, args ); } // Copy given type prototype linking to a new constructor Fn.prototype = constr.prototype || {}; // Mix-in members of given type to the new constructor's prototype xObject.mixin( Fn.prototype, members ); instance = new Fn(); // Call constructor function if any specified in __constructor__ property members.hasOwnProperty("__constructor__") && members.__constructor__.apply( instance, args || [] ); return instance; };

Slide 11

Slide 11 text

What about interfaces, mixins and so on? We add with a hook any object creation control flow that we wish. Let’s just change a bit the factory: xObject.create = function ( constr, args, props ) { ... instance = createInstance( constr, args, props ); xObject.hooks.invokeAll( instance, arguments ); return instance; };

Slide 12

Slide 12 text

xObject Way xObject is a light-weight library comprising factory plugins to “make of JavaScript the language I want”. Let’s see what they are.

Slide 13

Slide 13 text

Widget foundation class As good programmers we learn from the great ones, don’t we? So, let’s borrow from YUI guys some ideas of abstract widget (http://yuilibrary.com/yui/docs/widget/) . Videlicet: • Common bootstrap interface • Consistent node referencing • Built-in progressive enhancement support

Slide 14

Slide 14 text

Widget abstract layer in xObject Widget plugin declares xObject.WidgetAbstract, which makes the factory (via a hook) to auto- call bootstap methods (init, renderUi, bindUi, syncUi) of every class extending this one. It also populates node property with node references given in HTML_PARSER property of extending class

Slide 15

Slide 15 text

Usage example (function( xObject ) { Widget = function() { return { __extends__: xObject.WidgetAbstract, HTML_PARSER: { toolbar: 'div.toolbar' }, bindUi: function() { this.node.toolbar.querySelector('li') .addEventListener( 'click.intro', this.onClickListener, false ); }, onClickListener: function( e ) { // do something } }; }; // Document is ready document.addEventListener( "DOMContentLoaded", function() { xObject.create( Widget, { boundingBox: 'div.intro' } ); }, false); })( xObject );

Slide 16

Slide 16 text

Mixins Mixins provide aggregation (has-a) relation between objects, which is easy to implement especially is JavaScript. Mixin plugin only assigns a hook, which makes factory mix public members of objects given in __mixin__ property Mixin +init() +renderUI() +syncUI() -__extends__ -__mixin__ ConcreteClass 1 *

Slide 17

Slide 17 text

Usage example var MixinA = { propertyA: "propertyA" }, MixinB = { propertyB: "propertyB" }, Silo = function() { return { __mixin__: [ MixinA, MixinB ], ownPropery: "Own property" } }, o = xObject.create( Silo ); console.log( o.ownPropery !== undefined ); // true console.log( o. propertyA !== undefined ); // true console.log( o. propertyB !== undefined ); // true

Slide 18

Slide 18 text

Interfaces Interface plugin assigns a hook, which checks if the newly born object meets the requirements of the interfaces enlisted in __implements__ property. In order to make sure arguments match type hints, the plugin wrap the method with cross-cutting functionality, which does the check on entry point. -__implements__ ConcreteClass Interface *

Slide 19

Slide 19 text

Usage example var ConcreteInterface = { requeriedMethod : [ "string” ] }, StrictModule = function() { return { __implements__: ConcreteInterface, requeriedMethod : function() { } } }, o = xObject.create( StrictModule ); // Test Module.requeriedMethod( 'a string‘ ); // OK Module.requeriedMethod( 555 ); // throws TypeError exception

Slide 20

Slide 20 text

Design by Contract Design by Contract approach provides another and more sophisticated solution of defining requirements for the objects of a type. By a contract we can define entry/exit point conditions. -__contract__ ConcereClass Contract * var Contract = { methodName: { onEntry: [ "number", aClass ], // type hints validators: [ function( arg ) { return arg > 10; }, secondArgValidator ], onExit: "string" } }

Slide 21

Slide 21 text

Usage example var ConcreteContract = { methodA : { onEntry: [ "number" ], validators: [ function(arg){ return arg > 10; } ], onExit: "string" } }, EmployedModule = function() { return { __contract__: ConcreteContract, aMethod : function() { return "a string"; } } }, o = xObject.create( EmployedModule ); o.aMethod( 50 ); // OK o.aMethod( 1 ); // Validator fails, RangeError exception is thrown

Slide 22

Slide 22 text

Fork me! xObject project page: https://github.com/dsheiko/xObject Articles relevant to xObject http://dsheiko.com/weblog/js-application-design http://dsheiko.com/weblog/prototypal-inheritance- in-javascript-for-modules http://dsheiko.com/weblog/design-by-contract-and- js