javascript:

create.your.own('library');

Created by Paul Balchin






navigate

Esc bird's eye view

barbie.com's JavaScript library

Functions attached to object trees.


//SIMPLIFIED EXAMPLE
mattel = {};
mattel.loginreg = {};
mattel.loginreg.variables = {};
mattel.loginreg.login = function(){};
mattel.loginreg.logout = function(){};
mattel.loginreg.isUnder13 = function(){};
mattel.loginreg.isOver13 = function(){};
					

  1. There are no advantages to this structure
  2. All the functions are public
  3. None of the functions can share scope

What we really want are functions that look like objects

The humble function


var functionName = function(){
    console.log('called functionName()');
};
					

Call the function; get a result


//CONSOLE
functionName() → 'called functionName()'
						

The immediately-invoked function

Just add parens at the end


var functionName = function(){
    console.log('called functionName()');
}();
						

//CONSOLE 
'called functionName()'
						

Look ma, no hands!

You can wrap the entire function in another set of parens


var functionName = (function(){
    console.log('called functionName.init()');
}());
						

This is a matter of convention only

Think of it as a declaration

Popular ways to initialize a function

The set up


var functionName = (function(){
    console.log('called functionName()');
	
    var init = function(){
        console.log('called functionName.init()');
    };
    
    return {
        init: init
    };
}());
						

Call immediately


functionName.init(); 
							

Race conditions? External dependencies?


var functionName = (function(){
    console.log('called functionName()');
	
    var init = function(){
        console.log('called functionName.init()');
    };
    
    return {
        init: init
    };
}());
						

Call on document ready


$(document).ready(function(){
    functionName.init();
});
							

Where do you put it?


var functionName = (function(){
    console.log('called functionName()');
	
    var init = function(){
        console.log('called functionName.init()');
    };
    
    return {
        init: init
    };
}());
						

Call from somewhere in the HTML


<script>
    functionName.init();
</script>
							

Called from partials? Views? Layouts?

?

Initialize from within


var functionName = (function(){
    console.log('called functionName()');

    // this is an init()
    $(document).ready(function(){ 
        console.log('called functionName.document.ready()');
    });
}());
					

//CONSOLE
'called functionName()'
'called functionName.document.ready() '
					

  1. No need to create separate, public methods
  2. Has access to private (and scoped!) methods and properties

Various ways to initialize


var functionName = (function(){
    var a, b, c;
    var functionOne = function(){};
    var functionTwo = function(){};
    var functionThree = function(){};

    // types of inits(): event-driven
    $(document).ready(functionName);
    $(document).on('click',functionName);
    $(window).load(functionName);
    $(window).resize(functionName);
    
    // types of inits(): just call it 
    // (where race conditions don't apply)
    functionOne();
}());
					

Initialize with conditions


var functionName = (function(){
    var doSomethingWithHtml = function(){
        console.log('called functionName.doSomethingWithHtml()');
    };
    var doSomethingWithClick = function(){
        console.log('called functionName.doSomethingWithClick()');
    };

    $(document).ready(function(){
        // limit usage to specific HTML
        if( $('#htmlSelector').length > 0 ){ 
            doSomethingWithHtml();
        }
    });
}());
					

  1. Conditional initialization is best practice
  2. Proper use of CSS classes and IDs is very useful
  3. Functionality is tied to specific HTML, not specific pages

Initialize events


var functionName = (function(){
    var a, b, c;
    var onClickButtonOne = function(){};
    var onClickButtonTwo = function(){};
    var functionThree = function(){};
    var functionFour = function(){};
    
    $(document).ready(function(){
        // list of actions only, do the work above
        $(document).on('click', '#actionButtonOne', onClickButtonOne);
        $(document).on('click', '#actionButtonTwo', onClickButtonTwo);
    });
    $(window).load(function(){
        // list of actions only, do the work above
        functionThree();
    });
}());
					


//CONSOLE
functionName → 'undefined' // Wait. What?
					

You can't build a library on "undefined"


var functionName = (function(){
    console.log('called functionName()');
}());
					

//CONSOLE
'called functionName()'
functionName → 'undefined' // WHAT!?
					

Immediately-invoked functions that return nothing
are fire and forget

If you return nothing, then there's nothing to pass back to the variable name

A function can return one thing


var functionName = (function(){
    console.log('called functionName()');
	
    // return what?
}());
					

That's a pretty limited option.

  1. We need the option to return more than one thing
  2. We're still looking to build an object-based library

We return an object


var functionName = (function(){
    // everything is private by default
    var a, b, c;
    var functionOne = function(){};
    var functionTwo = function(){};
    var functionThree = function(){};
    
    // except what is returned as public here
    return { 
        FunctionOne: functionOne,
        FunctionTwo: functionTwo
    };
}());
					

//STRUCTURE
functionName → {
    FunctionOne: function (){},
    FunctionTwo: function (){}
}
					

Congratulations!

You've created a JavaScript namespace!


var namespace = (function(){
    var a, b, c;
    var functionOne = function(){};
    var functionTwo = function(){};
    var functionThree = function(){};
    
    return { 
        FunctionOne: functionOne,
        FunctionTwo: functionTwo
    };
}());
					

//STRUCTURE
namespace: {
    FunctionOne: function (){},
    FunctionTwo: function (){}
}
					
  1. A group of related variables and functions
  2. wrapped in another function (scope!)
  3. that looks like an object

Build your library of namespaces


var namespace = (function(){...}());
var namespace.nestedNamespace1 = (function(){...}());
var namespace.nestedNamespace2 = (function(){...}());
var namespace.nestedNamespace2.nestedNamespace2A = (function(){...}());
var namespace.nestedNamespace2.nestedNamespace2B = (function(){...}());
var namespace.nestedNamespace3 = (function(){...}());
                    

//STRUCTURE
namespace: {
    FunctionOne: function (){},
    FunctionTwo: function (){},
    nestedNamespace1: {
        FunctionOne: function (){},
    },
    nestedNamespace2: {
        FunctionOne: function (){},
        FunctionTwo: function (){},
        FunctionThree: function (){},
        NestedNamespace2A: function (){
            FunctionOne: function (){},
            FunctionTwo: function (){},
        },
        NestedNamespace2B: function (){},
    }
}
					

Build each namespace


var namespace = (function(){
    //scoped properties and variables,
    //scoped get/set functions for all public properties,
    //scoped core functions,
    //    for each core function
    //        scoped variables,
    //        exception handling
    //        code
    //initialization(s),
    //public declarations.
}());
                    

A namespace function that returns nothing?


var namespace = (function(){
    //scoped properties and variables,
    // --scoped get/set functions for all public properties,--
    //scoped core functions,
    //    for each core function
    //        scoped variables,
    //        exception handling
    //        code
    //initialization(s),
    // --public declarations.--
}());
                    
  1. Public declarations are created to respond to the needs of outside code.
  2. It's perfectly valid to build a function that can autonomously react to the outside world, à la fire and forget.
  3. But then, what's the point of adding it to the library? Maybe just organization.

"Micro management" vs. "Fire and forget"*

Micro management

  1. Create your library
  2. Decide which files will load on which layouts
  3. Decide which files will load on which pages
  4. Decide which files will load on which partials
  5. Decide how they will be bundled
  6. Decide how they will be loaded
  7. For each new page on the site, return to step 2
  8. For each addition to your library, return to step 2


* There are exceptions to every rule.

Fire and forget

  1. Create your library
  2. Bundle all your files together
  3. Load your entire library on each layout page

Keep it simple

  1. We load all of jQuery and plugins on every page
  2. We load all of our layout engine on every page
  3. Why not load all of our library on every page?

Thank You

(And there's more slides further on)

JavaScript tips

Comment your code

Liberally.

It won't add to the file size in production because minification will strip it out.

All JavaScript should be in *.js files

JavaScript files are cached by the browser

Strive for unobstrusive JavaScript

Noob


<span onclick="updateUserProfile();">Save your changes</span>
						

Pro


//HTML
<span class="updateUserProfile">Save your changes</span>

//JAVASCRIPT
$(document).on('click', '.updateUserProfile', onUpdateUserProfile});
						

Event handlers are your friends
(on click, on document ready, on window load, etc.)

Hoist your variables

  1. Functions are the only JavaScript objects that provide scope
  2. Always instantiate your variables at the top of each function
  3. Using "var" in an if statement or in the middle of a loop is asking for trouble
  4. Google "javascript hoisting" or go to http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html

JavaScript is not C#

In JavaScript, you usually create a variable for two reasons:

  1. You need to reference a value more than once,
  2. You need to maintain the readability of your code, and.Inserting().your('convoluted')[valueName] inside even more code makes it hard to make sense of.


You don't have to create a variable
for the sake of accessing a value.

jQuery tips

Don't use the $() shortcut

So similar,


$(object); // <-- example 1
$('selector', object); // <-- example 2
						

yet so far apart.


$(document).ready(callThisFunction); // <-- example 1 explained
$(jQueryObject).find('string'); // <-- example 2 explained
						

Don't be afraid to be verbose:

  1. Be kind to the next developer that will have to look at your code
  2. There's no performance difference, but it's much easier to read

CSS tips

Comment your code

Liberally.

It won't add to the file size in production because minification will strip it out.

No inline CSS

Noob


<div style="padding:10px;">
						

All CSS should be in *.css files

CSS files are cached by the browser

Use CSS classes and IDs to identify functionality

dashed-css-classes for styling


<div class="button-green">
<div class="list-of-products">
						

camelCaseClasses for JavaScript hooks


<div class="updateUserProfile">
<div class="expandCollapseProductDetails">
						

Mix and match


<div class="button-green updateUserProfile">
<div class="list-of-products expandCollapseProductDetails">
						

HTML tips

Layouts

Use <div> and <span> liberally for your layouts; search engines treat them as "scaffolding" tags and are not considered semantic markup.

The right tag for the job: Buttons

Buttons (<button> or <input type="button">) are form elements and are for submitting forms

(You can blame ASP.NET for their abuse. Read on.)

The right tag for the job: Anchors 1/3


//STANDARD USE
<a href="/product-details.html?id=345">Details for 345</a> 
						

Anchors are for linking one page to another, and the href is required. It is the only HTML tag search engines use to crawl your site if you don't provide them with a site map.

The right tag for the job: Anchors 2/3


//JAVASCRIPT INTERCEPTION
<a href="/product-details.html?id=345" 
   onclick="showModal(); return false;">Details for 345</a> 

// 1. Provides a URL for search engines to follow.
// 2. When clicked, the user sees a modal instead.
						

Event handlers, like onclick, are called first and the href last.

Be careful: If you don't return false (here or in the function), the browser will immediately follow the link.

The right tag for the job: Anchors 3/3

The right way


<a href="/product-details.html?id=345" 
   onclick="showModal(); return false;">Details for 345</a> 
						

The wrong way


<a href="#" onclick="showModalDetails('345');">Details for 345</a> 

// 1. Improper use of a named anchor, 
        e.g. href="#" means "scroll to top of page, then scroll to # on page".
// 2. No URL for search engines to follow.
// 3. If you don't "return false" you will:
//    a. add a "#" to the end of your URL (e.g. "yoursite.com/#")
//    b. add an entry to your browser's history
//       (ever click once but have to "go back" twice?)
						

An alternative way


<span onclick="showDetails('345');">Details for 345</span> 

// Any element can have event handlers.
						

End

`