Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Writing Maintainable and Reusable JavaScript

Writing Maintainable and Reusable JavaScript

It’s really easy for JavaScript files in a theme or plugin to quickly become a big, hairy mess. So let’s take a look at how to structure JavaScript code in a way that makes it easier to read and understand, easier to maintain, and prevents pollution of the global namespace. We’ll cover modular JavaScript structure and writing plugins.

Natalie MacLees

November 08, 2014
Tweet

More Decks by Natalie MacLees

Other Decks in Technology

Transcript

  1. Writing Maintainable & Reusable JavaScript
    by Natalie MacLees
    @nataliemac | nataliemac.com

    View Slide

  2. Why is maintainability important?

    View Slide

  3. JavaScript mistakes you’re probably making

    View Slide

  4. Writing all your code inside document ready
    jQuery(document).ready(function($){
    function slideShow() {
    // some code that makes a slideshow
    }
    !
    function newsTicker() {
    // some code that makes a news ticker
    }
    ...
    });

    View Slide

  5. Using global scope for all your variables and functions
    var newText = ‘Hello World’;
    !
    function addText() {
    var container = $(‘textContainer’);
    container.text(newText);
    }
    !
    var height = window.height();

    View Slide

  6. Inconsistently using style conventions
    var newText = ‘Hello World!”;
    !
    var some_other_text = “Hi there!”;
    !
    var yetSomeMoreText = “Bonjour!”;

    View Slide

  7. Not maintaining separation
    Click me!
    $(‘a’).css({

    ‘color’: ‘green’;

    ‘fontSize’: ‘2em’;

    });
    var lightbox = $(‘class=“lightbox”>title”>’);

    View Slide

  8. The wild, wild West of JavaScript

    View Slide

  9. Understandable
    Future-proof Readable
    Modifiable Extensible Testable
    What does maintainable & reusable mean?

    View Slide

  10. Writing better JavaScript
    1
    2
    3
    4
    5
    Style conventions
    Programming practices
    Modular pattern
    jQuery plugins
    Automation

    View Slide

  11. 1 Style conventions

    View Slide

  12. Spaces vs tabs

    View Slide

  13. Keep lines as short as possible
    if ( tod == ‘morning’ ) { $(‘.greeting’).text(‘Good
    morning’) } else { $(‘.greeting’).text(‘Good
    afternoon!’) }
    !
    $
    (‘ul’).slideDown().find(‘li’).addClass(‘open’).prepe
    nd(‘+’).end().addClass(‘parent-open’);

    View Slide

  14. Keep lines as short as possible
    $(‘ul’)
    .slideDown()
    .find(‘li’)
    .addClass(‘open’)
    .prepend(‘+’)
    .end()
    .addClass(‘parent-open’);

    View Slide

  15. Use comments like salt in soup

    View Slide

  16. Use logical names for functions and variables
    (even if they’re long)

    View Slide

  17. Use camelCase

    View Slide

  18. camelCase & abbreviations and acronynms
    getElementById()
    innerHTML()
    XMLHttpRequest()

    View Slide

  19. 2 Programming practices

    View Slide

  20. Keep layers separate
    CSS:
    .highlight {

    color: green;

    fontSize: 2em;

    }
    JavaScript:
    $(‘a’).addClass(‘highlight’);

    View Slide

  21. Keep layers separate

    {{title}}

    {{body}}


    View Slide

  22. Don’t modify objects you don’t own

    View Slide

  23. Event handlers should only handle events
    $(‘.next’).on(‘click’, function(){
    var slider = $(‘#slider’),
    currentSlide = slider.find(‘.current’),
    nextSlide = currentSlide.next();
    currentSlide.fadeOut();
    nextSlide.fadeIn();
    });

    View Slide

  24. Event handlers should only handle events
    $(‘.next’).on(‘click’, function(){
    nextSlide();
    });
    !
    function nextSlide() {
    // code to advance to next slide here
    }

    View Slide

  25. Throw your own errors
    Twitlicious.addTweets = function(container) {
    if ( container instanceof jQuery) {
    container.append(Twitlicious.tweets);
    } else {
    throw new Error “addTweets: This is not a jQuery
    object!”;
    }
    }

    View Slide

  26. Separate config data
    var config = {
    url: ‘https://api.twitter.com/...',
    tweetsToShow: 5,
    tweetContainer: $(‘#tweets’)
    };

    View Slide

  27. Avoid global functions & variables

    View Slide

  28. 3 Modular Pattern

    View Slide

  29. Object literal
    var projectName = {
    config: {
    numberofTweets: 5,
    url: ‘http://api.twitter.com...',
    container: $(‘tweets’)
    },
    init: function() {
    // get everything going
    },
    ...

    View Slide

  30. Object literal
    jQuery(function(){
    projectName.init();
    };
    !
    var projectName = {
    config: {
    ...
    },
    init: function() {
    // initialize the project
    }
    }

    View Slide

  31. Immediately invoked function expression (IIFE)
    ;(function ($, projectName, undefined) {
    var linkClick = function() { // private
    $(‘a’).on(‘click’, function(){
    //do something when links are clicked
    });
    };
    projectName.init = function() { // public
    linkClick();
    };
    }(jQuery, window.projectName = window.projectName || {}));
    !
    jQuery(function(){
    projectName.init();
    });

    View Slide

  32. 4 jQuery plugins

    View Slide

  33. Use an immediately invoked function expression
    ;(function($){
    $.fn.venturaSlider = function(options){
    // Plugin code goes here
    }
    })(jQuery);

    View Slide

  34. window, document, undefined
    ;(function($, window, document, undefined){
    $.fn.venturaSlider = function(options){
    // Plugin code goes here
    }
    })(jQuery, window, document);

    View Slide

  35. Iterate over each item in the collection
    ;(function($, window, document, undefined){
    $.fn.venturaSlider = function(options){
    this.each(function(){
    // Do something to each item
    });
    }
    })(jQuery, window, document);

    View Slide

  36. Use .data() to store instance details
    ;(function($, window, document, undefined){
    $.fn.venturaSlider = function(options){
    this.each(function(){
    var $this = $(this);
    $this.data(‘current’, 1);
    });
    }
    })(jQuery, window, document);

    View Slide

  37. Allow customization & use extend()
    ;(function($, window, document, undefined){
    $.fn.venturaSlider = function(options){
    var opts = $.extend( {},
    $.fn.venturaSlider.defaults, options);
    ...
    }
    $.fn.venturaSlider.defaults = {
    // Define default settings
    };
    })(jQuery, window, document);

    View Slide

  38. Return the jQuery object for chaining
    ;(function($, window, document, undefined){
    $.fn.venturaSlider = function(options){
    var opts = $.extend( {},
    $.fn.venturaSlider.defaults, options);
    ...
    return this;
    }
    $.fn.venturaSlider.defaults = {};
    })(jQuery, window, document);

    View Slide

  39. 5 Automation

    View Slide

  40. Break JavaScript into multiple files

    View Slide

  41. Minify, compress, & deploy

    View Slide

  42. Maintainable & reusable code matters
    1
    2
    3
    4
    5
    Style conventions
    Programming practices
    Modular pattern
    jQuery plugins
    Automation

    View Slide

  43. –Rick Osborne, creator of TorrentSpy
    “Always code as if the person
    who ends up maintaining your
    code is a violent psychopath
    who knows where you live.”

    View Slide

  44. –Chris Eppstein, creator of Compass
    “Be kind to your future self.”

    View Slide

  45. Thank you!
    Questions?

    View Slide