Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Choosing an OOP pattern in javascript

I've put these together with the help of others and several resources. I've made a fiddle of everything, and the stripped down code is posted below.

Basically I've learned how to use each of these patterns but I'm curious about the more fundamental differences between these approaches. Downstream code is practically identical with any of these patterns, but is there a reason why one should use one over another, beyond personal preference? Also though I've tried to gather up the most common patterns, please suggest your own if it's better.

Pattern 1 (Object Based):

var mouseDiff = {
    "startPoint" : {"x" :0, "y" : 0},
    "hypotenuse" : function(a,b) {
        // do something
    },
    "init"       : function(){
        // do something
    }
}

mouseDiff.init();

Pattern 2 (Most traditional as far as I know):

function MouseDiff() {
    this.startPoint = {"x" :0, "y" : 0};
}

MouseDiff.prototype.hypotenuse = function(a,b) {
    // do something
}

MouseDiff.prototype.init = function() {
    // do something
}

var myMouse = new MouseDiff;
myMouse.init();

Pattern 3 (Making use of closure):

var MouseDiff2 = (function() {
    var startPoint = {"x" :0, "y" : 0};
    var hypotenuse = function(a,b) {
        // do something
    };
    return {
        hypotenuse: hypotenuse,
        init : function(){
            // do something
        }
    };

}());
MouseDiff2.init();
like image 349
Radu Avatar asked Jun 14 '11 19:06

Radu


People also ask

How should we design objects in JavaScript?

Common ways to create objects in JavaScript are the three following ways: // either of the following ways can be used to create a new object var instance = {}; // or var instance = Object. create(Object. prototype); // or var instance = new Object();


2 Answers

Pattern 1 is a singleton. If you only need one such object, it's just fine.

Pattern 2 builds new objects, and takes advantage of the prototype object so that when a new MouseDiff object is created, it will not create new copies of the functions (which are themselves data in JavaScript).

Pattern 3 requires more memory in comparison to a regular singleton but it offers static privacy.

I like the following pattern, as it covers various features, though it is really a combination of the constructor (pattern 2) and closure (pattern 3):

var MouseDiff = (function () {

    var aStaticVariable = 'Woohoo!';
    // And if you really need 100% truly private instance
    // variables which are not methods and which can be
    // shared between methods (and don't mind the rather
    // big hassle they require), see
    // http://brettz9.blogspot.com/search?q=relator
    // (see also the new plans for a Map/WeakMap in ECMAScript)

    function _APrivateStaticMethod () {
        alert(aStaticVariable);
    }

    // An instance method meant to be called on the
    //   particular object as via ".call(this)" below
    function _APrivateInstanceMethod () {
        alert(this.startPoint.x);
    }

    // Begin Constructor
    function MouseDiff() {
        this.startPoint = {"x" :0, "y" : 0};
    }

    MouseDiff.prototype.hypotenuse = function(a,b) {
        // do something
    };

    MouseDiff.prototype.init = function() {
        // do something
        _APrivateStaticMethod(); // alerts 'Woohoo!'
        _APrivateInstanceMethod.call(this); // alerts 0 (but if not
        // called with this, _APrivateInstanceMethod's internal
        // "this" will refer (potentially dangerously) to the
        // global object, as in the window in the browser unless
        // this class was defined within 'strict' mode in which
        // case "this" would be undefined)
    };

    return MouseDiff;
}());

var myMouse = new MouseDiff;
myMouse.init();
like image 99
Brett Zamir Avatar answered Sep 29 '22 11:09

Brett Zamir


I do not know enough about JavaScript to tell you what if any performance differences exist between these approaches. Here are just two differences between these I noticed. I'm sure there are others.

Pattern 1 creates one object with those properties, including attached methods. Pattern 2 allows us to easily create many objects with the same methods attached, without rewriting them.

Pattern 3 is like a factory. Instead of relying on prototype to automatically attach these methods, the factory just creates them anew and returns the object. The usage of a closure allows us to hide the "member variables" of the object. There is no way to access startPoint or hypotenuse() except through the "public" interface returned.

Whenever I answer these types of theoretical JavaScript questions, I always fear there is some technical detail I am forgetting or overlooking. If so, let me know, and I will fix the answer.

like image 33
TNi Avatar answered Sep 29 '22 10:09

TNi