(English) Understanding JS Notes 08: Making your own framework


Rất tiếc, mục này chỉ tồn tại ở Tiếng Anh (Mỹ). For the sake of viewer convenience, the content is shown below in the alternative language. You may click the link to switch the active language.

So I finished the course!

The last couple of lessons weren’t too much to write about because they were just random odds and ends and then just reading through jQuery code. Honestly the part with the jQuery code I kind of zoned out on, but it all kind of came together at the end where we built our own mini library.

Below you can see my whole code in its entirety. The key takeaways from this I think were that

  1. Put your code in an IIFE so that your variables don’t collide with other code
  2. Keep vars that you don’t want others to have access to outside of your methods / prototypes
  3. To create chainable actions, you need to return your object (this) for each function.
  4. To create something like jQuery, where you don’t want have to use newall the time, you should build that functionality in your framework by having the framework do that itself by returning a new function (which then creates the object you want)
    1. In this setup, you have two functions. Greetr which simply returns a new object based on the Greetr.init function. If we want to give that object access to some methods, then you could point the Greeter.init.prototype to Greeter.prototype. Then you add some methods to Greetr.prototype and because of the prototype chain, new Greetr objects will have access to them and it looks a little cleaner/less typing.
  5. Remembering that when new is called on a function constructor, the JS engine builds a new object and assigns that to this. You can then use this to build your own object to return. Remember that when functions are inside functions, the this can change (usually back to the global object) so to avoid that, create a new var like self and set it to this. Then use self throughout the code to make sure it’s consistently referring to the same object. As I’m writing this part, I realized we actually only did that during the creation of the first object and after that we used this in all of our methods. It seems to me that wasn’t really necessary, as we didn’t have functions nested in functions with our object.
  6. To set our method on the global object, we need to make sure that the global object is passed into our method and then at the end we can make it available by setting our method as a part of the global object. If you want to be able to use a shorthand like how jQuery uses $, then all you have to do is set global.$ = yourMethod

 


(function(global, $) {

    var Greetr = function(firstName, lastName, language) {
        return new Greetr.init(firstName, lastName, language)
    }
    var supportedLangs = ['en', 'es'];

    var greetings = {
        en: 'Hello',
        es: 'Hola'
    };

    var formalGreetings = {
        en: 'Greetings',
        es: 'Saludos'

    };

    var logMessages = {
        en: 'Logged in',
        es: 'Incio sesion'
    }

    Greetr.prototype = {
        fullName: function() {
            return this.firstName + ' ' + this.lastName;
        },
        validate: function() {
            if (supportedLangs.indexOf(this.language) === -1) {
                throw "Invalid language"
            }
        },

        greeting: function() {
            return greetings[this.language] + ' ' + this.firstName;
        },
        formalGreeting: function() {
            return formalGreetings[this.language] + ' ' + this.fullName();
        },

        greet: function(formal) {
            var msg;

            if (formal) {
                msg = this.formalGreeting();
            } else {
                msg = this.greeting();
            }
            if (console) {
                console.log(msg);
            }
            return this;
        },
        log: function() {
            if (console) {
                console.log(logMessages[this.language] + ': ' + this.fullName());
            }
            return this;
        },
        setLang: function(lang) {
            this.language = lang;
            this.validate();
            return this;
        },
        HTMLGreeting: function(selector, formal) {
            if (!$) {
                throw 'jQuery not loaded';
            }

            if (!selector) {
                throw 'No selector!'
            }
            var msg;
            if (formal) {
                msg = this.formalGreeting();
            } else {
                msg = this.greeting()
            }

            $(selector).html(msg);
            return this;

        }

    };

    Greetr.init = function(firstName, lastName, language) {
        var self = this;
        self.firstName = firstName || "";
        self.lastName = lastName || "";
        self.language = language || "en";
    }

    Greetr.init.prototype = Greetr.prototype;

    global.Greetr = global.G$ = Greetr;


}(window, jQuery));