samedi 30 septembre 2017

Best Practices for Writing Reusable Javascript Libraries

I wonder as a developer if someone asks me:

"What are the best practices to use when creating a reusable javascript library?"

what would I answer?
I have my own answer to this question, but I thought it would be very nice to share it and see where did I got it wrong, or could do it better and etc.
I am thankful to anyone who takes time to read and share his/her ideas.

What I've been doing so far:

I- Anytime that I wrote a Javascript library, which I want to have new instances of it every time that I want to use it, I do the following:

var MyNamespace = (function(){

    var MyFirstClass = (function(){
        function MyFirstClass(){
            var self = this;
            var class_configuration_object = {
                first_property: 'default value'
            };

            // configuration getter
            this.GetConfiguration = function(){
                return class_configuration_object;
            }; 

            // I NEVER use a setter for whole of my configuration object
            this.SetConfiguration = function(){};

            // I write setters and getters for whatever is inside the configuration object, like so:
            // BTW, I Love Chaining Setters.
            this.SetFirstProperty = function(first_property){
                class_configuration_object.first_property = first_property;
                return self;
            };

            this.GetFirstProperty = function(){
                return class_configuration_object.first_property;
            };
        }

        // static methods:
        MyFirstClass.StaticMethod1 = function(){};
        .
        .
        .

        // private functions:
        // when using private functions inside instance methods,
        // I pass this to the private functions always as the first argument.
        // because then self always safely points to the MyFirstClass object.
        var privateFunction1 = function(self){};
        .
        .
        .

        // instance methods:
        MyFirstClass.prototype.InstanceMethod1 = function(){
            // method logic here
            return this;
        };
        .
        .
        .


        return MyFirstClass;
    }());

    var MySecondClass = (function(){
        .
        .
        .
    }());

    return {
        MyFirstClass: MyFirstClass,
        MySecondClass: MySecondClass
    };

}()) ;

then simply you can use MyFirstClass like so:

// instantiating MyFirstClass with default config
var obj = new MyNamespace.MyFirstClass();

// setting configuration object properties:
obj.SetFirstProperty('some value');

// calling instance methods:
obj.InstanceMethod1();

// now because the setters return the object itself, you can also do:
var obj = new MyNamespace.MyFirstClass()
                        .SetFirstProperty('some value')
                        .InstanceMethod1();

II- those times that I want to have a consistent and shared behavior everywhere, I use the following:

var MyLib = (function(){
    // private variables:
    var privateVariable1 = 'default value';

    // public variables:
    var PublicVariable1 = 'default value';

    // private functions:
    var privateFunction1 = function(){};

    // public methods:
    var PublicMethod1 = function(){};

    return {
        PublicVariable1: PublicVariable1,
        PublicMethod1: PublicMethod1
    };

}());

So you can use it like:

// I use this pattern when I want to have a consistant behavior
// that always does the same thing for all of it pointers
// for example:

var a = MyLib;
var b = MyLib;

console.log(a.PublicVariable1); // outputs 'default value'
console.log(b.PublicVariable1); // outputs 'default value'

MyLib.PublicVariable1 = 'new value';

console.log(a.PublicVariable1); // outputs 'new value'
console.log(b.PublicVariable1); // outputs 'new value'

// here MyLib always returns an object, not a constructor.
// that's why you can never do the following here:
var obj = new MyLib(); // a TypeError obviously!

Aucun commentaire:

Enregistrer un commentaire