Javascript Notebook
  • Introduction
  • Intro to JavaScript
    • Section 1 - Getting Started
    • Section 2 - Execution Contexts and Lexical Environements
    • Section 3 - Types and Operators
    • Section 3 Part 2 - Closures and Callbacks
    • Section 4 - Objects and Functions
    • Section 5 - Object Oriented Javascript and Prototypal Inheritance
    • Section 6 - Building Objects
    • Section 7 - Odds and Ends
    • Section 8 - Examining Famous Frameworks and Libraries
    • Section 9 - Let's Build a Framework or Library!
  • Midterm Review
  • Final Review
  • jQuery
    • Section 1 - Selectors
    • Section 2 - Events
    • Section 3 - Effects
  • Node.js
    • The Node Core
    • Modules, Exports, and Require
    • Events and the Event Emitter
    • Databases and SQl
  • D3.js
    • Diving In
    • Bar Chart
    • Creating A Complex Bar Chart
Powered by GitBook
On this page
  • Building Our own Framework
  • Part 3
  • Part 3
  • The Final Library/Framework

Was this helpful?

  1. Intro to JavaScript

Section 8 - Examining Famous Frameworks and Libraries

Building Our own Framework

Requirements

  • Name: Greetr

  • Generates form and informal greetings

  • Reusable, and non interfearing

  • English and Spanish

  • Easy to Type structure

    • $G

  • Support Jquery

Structuring safe code

    ...


    (function (global, $){

    })(window, $)
  • What happened:

    • Immediately invoked function that creates a new execution context, keeping our variables safe.

    • 2 global objects where passed that we're going to work with.

Part 2

    (function (global, $){

        var Greetr = function(first, last, lang) {
            return new Greetr.init(first, last, lang);
        }
    }
  • Greetr is a function, that when invoked, returns a new object, so that we do have to use the keyword ourselves.

  • Init is not yet defined, but is a common keyword used to handle initialization.

    (function (global, $){

        var Greetr = function(first, last, lang) {
            return new Greetr.init(first, last, lang);
        }

        Greetr.prototype = {};

        Greetr.init = function(first, last, lang) {
            this.firstname = first || '[users first name]';
            this.lastname = last || '[users last name]';
            this.language = lang || 'en';

            // defined later -> checks if language is supported
            this.validate();
        }

        Greetr.init.prototype = Greetr.prototype;

    })(window, $)
  • Next we implement our object constructor.

    • Unique variable primitive to our library are defined as a properties to each respected object.

      • Default variables are invocated by coersion.

  • We defined a new object as a prototype (inheritance) to each object.

    • Save memory space by not passing it into the constructor.

    • Empty for now

  • Because objects where constructed with .init (seperate execution context), we want all Greetr/prototype objects to point to Greetr.init.prototype.

    • Allows us to define methods in Greetr.prototype more cleanly.

        global.Greetr = global.$G = Greetr;
  • One last thing before we finish. To establish a neat alias, all we have to set our object function constructor as part of the global window.

  • Now, we can treat Greetr, and $G equivalently as constructors.

    var g = $G('dan','mak');
    console.log(g); // G…r.init {firstname: "dan", lastname: "mak", language: "en"}

Part 3

    var supportedLang = ['en', 'es'];

        Greetr.prototype = {

    };
  • The next part is really cool. Its just like constructing classes in C++.

  • Each unique object will have access to methods defined without our prototype, thanks to our pointer fix.

  • Variables constructed WITHIN the immediately invoked function will remain 'private' to the methods within the prototype.

    • That way, our framework is defined where it needs to be, and does not mess around with any global context.

    • Our prototype, however - maintains access to these variables because of closure.

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

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

    var logMessages = {
        en: 'Logged In',
        es: 'Inicio sesion'
    };
  • Next, we define a few reference variables for our prototype methods.

    fullname: function() {
        return this.firstname + ' ' + this.lastname;
    },

    validate: function() {
        if (supportedLang.indexOf(this.language) === -1) {
            throw "Invalid language";
        }
        else {
            console.log("Valid 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();
        }

        //show whats happening
        if (console) {
            console.log(msg);
        }

        return this;
    },

    log: function() {
        //Internet explore check if console is open
        if (console) {
            console.log(logMessages[this.language] + ' ' + this.fullname());
        }

        //chainable
        return this;
    },

    setLang: function(lang) {
        this.language = lang;
        this.validate();
        return this;
    } 
  • Each of these functions will reference with a uniquely constructed new object.

  • This is why the keyword this becomes so important.

  • validate searches through our index of supported languages with this.language, - the current language supplied to an object.

    • throws and error if the language is invalid.

  • function greet is not required, but it grants chainable methods to our library. It also simplifies two methods with a single invocation

    • Optional boolean variable passed in to invoke a formal greeting.

  • At first I thought it was strange that setLand first let the language, and then validated it, but then I realized something.

    • Even if we change the language of an object to something that is not supported, it does not matter because it of this.validate().

    • If an error is thrown, then the setLand does not return, so it wouldn't allow it to pass through.

  • Testing so far

    var a = g.fullname();
    console.log(a); // dan mak

    g.validate(); // Valid language

    var b = g.greeting(); 
    console.log(b); // Hello dan!

    var c = g.formalGreeting();
    console.log(c); // Greetings dan!

    g.greet(); // Hello dan!

    g.log(); // Logged In dan mak

    g.setLang('germen');
    g.validate(); //Uncaught Invalid language

Part 3

  • Adding jQuery support

EnglishSpanish

    HTMLGreeting: function(selector, formal) {
        if (!$) {
            throw 'Jquery not loaded';
        }

        if (!selector) {
            throw 'Missing Jquery selector';
        }

        var msg;
        if (formal) {
            msg = this.formalGreeting();
        }
        else {
            msg = this.greeting();
        }

        $(selector).html(msg);
        return this;
    }
  • This function will be used to modify our html page once all of our variables are taken into account. The selector is a jQuery element.

    • Everything else references variables that are already known in the constructed object.

    • We also have a bit of jQuery code on the bottom, that is used to modify any html attribute.

  • It is always best to commenet up your code once you finish. It may be understood now, but in time - the memory of your intents may be lost.

  • It also helps other coders.

  • Since I've documented my thoughts here, I wont bother.

    $('#login').click(function() {
        var g = $G('dan','mak');
        var loginGreeter = g;

        $('#logindiv').hide();
        loginGreeter.setLang($('#lang').val()).HTMLGreeting('#greeting', true).log();
    });
  • Finally, its time to finish up our project by adding jQuery functionality to our html.

  • That long chained method looks complecated, but lets break it down:

    • Using our constructed object, we set our variable property using a jQuery selector on the html element.

    • The next function call can be thought of as being executed on a new line.

The Final Library/Framework

    //HTML
    <html>
    <head>

    </head>
    <body>
        <div id="logindiv">
            <select id="lang">
                <option value="en">English</option> 
                <option value="es">Spanish</option> 
            </select>
            <input type="button" value="Login" id="login">
        </div>

        <h1 id="greeting"></h1>

        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
        <script src="Greetr.js"></script>
        <script src="app.js"></script>
    </body>                                            
    </html>


    //Greetr.js
    (function (global, $){

        var Greetr = function(first, last, lang) {
            return new Greetr.init(first, last, lang);
        }

        var supportedLang = ['en', 'es'];

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

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

        var logMessages = {
            en: 'Logged In',
            es: 'Inicio sesion'
        };

        Greetr.prototype = {
            fullname: function() {
                return this.firstname + ' ' + this.lastname;
            },

            validate: function() {
                if (supportedLang.indexOf(this.language) === -1) {
                    throw "Invalid language";
                }
                else {
                    console.log("Valid 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();
                }

                //show whats happening
                if (console) {
                    console.log(msg);
                }

                return this;
            },

            log: function() {
                //Internet explore check if console is open
                if (console) {
                    console.log(logMessages[this.language] + ' ' + this.fullname());
                }

                //chainable
                return this;
            },

            setLang: function(lang) {
                this.language = lang;
                this.validate();
                return this;
            },

            HTMLGreeting: function(selector, formal) {
                if (!$) {
                    throw 'Jquery not loaded';
                }

                if (!selector) {
                    throw 'Missing Jquery selector';
                }

                var msg;
                if (formal) {
                    msg = this.formalGreeting();
                }
                else {
                    msg = this.greeting();
                }

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

        };

        Greetr.init = function(first, last, lang) {
            this.firstname = first || '[users first name]';
            this.lastname = last || '[users last name]';
            this.language = lang || 'en';

            // check language
            this.validate();
        }

        Greetr.init.prototype = Greetr.prototype;

        global.Greetr = global.$G = Greetr;

    })(window, $)



    //app.js


    $('#login').click(function() {
        var g = $G('dan','mak');
        var loginGreeter = g;

        $('#logindiv').hide();
        loginGreeter.setLang($('#lang').val()).HTMLGreeting('#greeting', true).log();
    });
PreviousSection 7 - Odds and EndsNextSection 9 - Let's Build a Framework or Library!

Last updated 5 years ago

Was this helpful?