Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Bringing classical OOP into JavaScript

Bringing classical OOP into JavaScript

Any diligent developer is constantly working on improving his or her code. There are plenty of books telling how to make your code better. However most of them use the language of class-based OOP. Reader must have enough of experience to reflect those classical design patterns on JavaScript. Thus, many and many developers give up on the language before mastering its true power. On the other hand, JavaScript is an incredible impressive language. I wonder if JavaScript was originally designed as a foundation on which you build your own language.

About 2 years ago I had worked out a solution which developed by now into a light-weight library which brings into JavaScript everything I miss in the language as a follower of class-based OOP. All about how it is implemented and how can be used is on the slides.

Dmitry Sheiko

June 01, 2012
Tweet

More Decks by Dmitry Sheiko

Other Decks in Programming

Transcript

  1. Who's the dude? I'm Dmitry Sheiko, a web developer, blogger,

    open source contributor. http://dsheiko.com @sheiko https://github.com/dsheiko
  2. Reflecting learnt patterns on JavaScript What the hell?! Where are

    all the classes, interfaces, members visibility, namespaces, mixins?!
  3. 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
  4. 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
  5. 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();
  6. 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; } } }
  7. 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; };
  8. 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; };
  9. 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.
  10. 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
  11. 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
  12. 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 );
  13. 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 *
  14. 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
  15. 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 *
  16. 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
  17. 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" } }
  18. 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
  19. 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