KEMBAR78
Responsible JavaScript | PDF
Responsible JavaScript
    Refresh NYC — January 2010




                                 1
Where should I get started?
 •   Globals          •   switch () {...}

 •   Namespaces       •   Equality

 •   Prototypes
                      •   $

 •   Factories

 •   this

 •   Incrementing &
     Decrementing


                                            2
Globals



          http://www.lovemikeg.com/blog/2010/01/19/responsible-javascript-globals/
                                                                                 3
Globals have a bad
reputation.


                     4
Where possible, just
avoid them.


                       5
(function () {

  var printMe;

  printMe = document.getElementById(‘print-me’);
  printMe.addEventListener(‘click’, function () {
    window.print();
    return false;
  }, false);

})();




                                                    6
In all other cases,
simply don’t pollute.


                        7
Rules for Responsible Globals


Namespace everything.
Only one global per library.
Only one global per application.




                                   8
Good libraries...


When choosing a library, choose a responsible
one.
   •   jQuery w/compatibility mode is great

   •   YUI is also a great choice




                                                9
Good applications...

Keep it simple: each app gets a global
In most cases, a site == an app
In other cases, a page == an app
   •   searchResults

   •   userProfile

   •   shoppingCart


                                         10
Namespaces



       http://www.lovemikeg.com/blog/2010/01/20/responsible-javascript-namespaces/
                                                                                 11
Namespaces are a
really good idea.


                    12
jQuery.ajax(…)



                 13
Namespaces can get
out of control. Fast.


                        14
com.foo.utils.appManager
  .myApp.widgets
  .contactForm.validate();




                             15
Responsible Namespaces

Use a namespace creator function
Segregate application namespaces from library
namespaces
Organize libraries into component groups
Organize applications into functional groups



                                                16
This might seem like a good
idea…


      var myNS = { … };



   …until you have multiple
     modules in myNS.
                              17
How do you do this reliably?


  myNS.myModule = { … };




                               18
How do you do this reliably?


var myNS = window.myNS || {};
myNS.myModule = {};




                                19
This is a better idea:


   foo.namespace(‘myNS.myModule’);




                                     20
Applications vs. Libraries

Applications are living, breathing structures
which must be accepting to change both
internally and externally.
Libraries are shared dependencies and must be
be organized in a stable structure so as to
minimize the need for change at all.



                                                21
In other words...

You application will be a self-contained entity
which is made up of lots of smaller
components.
   •   Don’t be strict and rigid with your app
       namespaces.

   •   References to other apps are common, keep app
       namespaces shallow.



                                                       22
Prototypes



      http://www.lovemikeg.com/blog/2010/01/21/responsible-javascript-prototype-modification/
                                                                                          23
Prototypes are
powerful.
Really powerful.


                   24
“With great power there must
also come… great responsibility!”
  — Amazing Fantasy #15 (The first Spider-Man story)




                                                      25
“Yeah, but I want convenience.”

Array.prototype.each = function (callback) {
    for (var i = 0, l = this.length; i < l; i++) {
        callback(this[i], i);
    }
};




                                                     26
Think it through…


Is it proper to cast your dependencies on the
language itself?
How/Where is this documented? Is it obvious
to your team?
Are there any other unintended consequences?



                                                27
How many members in foo?
Object.prototype.count = function () {
    var count = 0;
    for (var i in this) count++;
    return count;
};

console.log(
    {'foo':12345}.count()
);




                                         28
Go ahead. Say it.


“But you should be using Object.hasOwnProperty.”
   •   Yeah but does anyone actually do that?

   •   Do you feel comfortable assuming that all future
       developers on your project will know that?




                                                          29
A better option is to
simply extend.


                        30
var MyArray = function () {};
MyArray.prototype = new Array;




                                 31
Factories



            http://www.lovemikeg.com/blog/2010/01/22/responsible-javascript-using-factories/
                                                                                          32
Factories are your
friends.


                     33
Factories manage complexity.


…and anything that reduces complexity should
be considered a best practice right?
Factories can also:
   •   Make your code safer

   •   Make your code faster




                                               34
Factories are a safety measure.

 var Person = function (name, location) {
     this.name = name;
     this.location = location;
 };

 var mike = new Person('Mike G.', 'NYC');
 var alex = Person('Alex H.', 'NYC'); // oops!




                                                 35
Constructors are simply
broken.

Forgetting the new keyword can be disastrous.
Best case scenario, a few globals spill out.
Worst case scenario, your app stops working.




                                                36
Problem solved.

Person.factory = function (name, location) {
  return new Person(name, location);
}

var mike = new Person.factory('Mike G.', 'NYC');
var alex = Person.factory('Alex H.', 'NYC');




                                                   37
this


       http://www.lovemikeg.com/blog/2010/01/23/responsible-javascript-using-this/
                                                                                 38
this  has an identity
crisis.


                        39
var foo = {
  ‘bar’ : 12345,

     ‘getBar’ : function () {
        return this.bar;
     },

     ‘onclickCallback’ : function () {
        window.open(this.href);
        return false;
     },

     ‘wtf’ : function () {
       return {
          ‘hello’ : ‘world’,
          ‘sayHi’ : function () {
            return this.hello;
          }
       };
     }
};

                                         40
this is ambiguous

It refers to the object in which its defined.
Unless:
   •   It’s copied (referenced) to another object

   •   It’s used as an event handler (sometimes).

   •   You .call or .apply it.




                                                    41
Best practices

Know your namespace. Be explicit.
Fix your events.You can never be too sure.
Keep your event handlers in a separate object.
Document all irregularities (including event
handlers).



                                                 42
Incrementing &
Decrementing


                 43
++ and -- have a bad
reputation… to some.


                       44
“The ++ (increment) and -- (decrement) operators
have been known to contribute to bad code by
encouraging excessive trickiness. They are second only
to faulty architecture in enabling to viruses and other
security menaces.”

                             —Douglas Crockford
                               http://www.jslint.com/lint.html#inc




                                                                     45
Trickiness like...
var a = 1;
var b = 2;
var c = 3;

console.log(a++ + b == c);
console.log(a + ++b == c);
console.log(a + + + b == c);

console.log(a, b, c);




                               46
Suggestions


Don’t write tricky code like that.
   •   Probably your best bet ;)
Don’t use incrementors/decrementors
   •   There’s nothing wrong with +=   1




                                           47
switch () {...}



                  48
switch can break if
you don’t break.


                      49
function dateSuffix(date) {
    switch (date){
        case (1) : case (21) : case (31):
            dt = "st";
            break;

        case (2) : case (22):
            dt = "nd";
            break;

        case (3) : case (23):
            dt = "rd";
            break;

        default: dt = "th";
    }

    return date + suffix;
}



                                            50
… is the same as…



                    51
function betterDateSuffix (date) {
    if (date === 1 || date === 21 || date === 31) {
        return date + 'st';
    }
    else if (date === 2 || date === 22) {
        return date + 'nd';
    }
    else if (date === 3 || date === 23) {
        return date + rd;
    }
    else {
        return date + 'th';
    }

    return date + suffix;
}




                                                      52
and …



        53
function yetAnotherDateSuffix   (date) {
    var suffixMap = {
        'st' : (date === 1 ||   date === 21 || date === 31),
        'nd' : (date === 2 ||   date === 22),
        'rd' : (date === 3 ||   date === 23),
        'th' : true
    };

    for (var suffix in suffixMap) {
        if (suffixMap[suffix]) {
            return date + suffix;
        }
    }
}




                                                               54
Which is better?

Depends on your team’s coding standards.
I suggest:
   •   The one which is easiest to understand.

   •   The one which is easiest to change.



(I like the third option, personally.)


                                                 55
Equality



           56
Equality isn’t as easy as
you think.


                            57
Take your best guess
console.log(false   ==   -1);
console.log(false   ==   -0);
console.log(false   ==   0);
console.log(false   ==   []);
console.log(false   ==   "");
console.log(false   ==   "0");
console.log(false   ==   null);
console.log(false   ==   undefined);
console.log(false   ==   null);




                                       58
Take your best guess
console.log(false   ==   -1);          //   false
console.log(false   ==   -0);          //   true
console.log(false   ==   0);           //   true
console.log(false   ==   []);          //   true
console.log(false   ==   "");          //   true
console.log(false   ==   "0");         //   true
console.log(false   ==   null);        //   false
console.log(false   ==   undefined);   //   false
console.log(false   ==   null);        //   false




                                                    59
Just use === or !==


Your code will be less ambiguous
Your code will run faster
   •   No need to convert types




                                   60
$



    61
Developers love $.



                     62
The problem, is that everyone
loves $.

Brought to you by Prototype
Made famous by jQuery


But what happens if you include jQuery and
Prototype on the same page?



                                             63
The Specs say...



“$ is reserved for implementations”
   •   Whatever that means.




                                      64
Fact: $ is perfectly valid.



                              65
“Just don’t do that.”


Yeah. Easier said than done.
   •   Try talking your client its better to rewrite the
       widget written in another library

   •   They like their $$ too.




                                                           66
Just don’t be irresponsible.


Give your devs a choice to use it or not
Never write applications that assume $
Always assume control over $




                                           67
There is hope.

jQuery has compatability mode.
   •   Please use it.

   •   Develop your apps as if you’re writing a plugin…
       var myApp = (function ($) {
         // Your code goes here.
       })(window.jQuery);


YUI is a nice choice too ;)


                                                          68
Thank you.
mikeg@lovemikeg.com




                      69

Responsible JavaScript

  • 1.
    Responsible JavaScript Refresh NYC — January 2010 1
  • 2.
    Where should Iget started? • Globals • switch () {...} • Namespaces • Equality • Prototypes • $ • Factories • this • Incrementing & Decrementing 2
  • 3.
    Globals http://www.lovemikeg.com/blog/2010/01/19/responsible-javascript-globals/ 3
  • 4.
    Globals have abad reputation. 4
  • 5.
  • 6.
    (function () { var printMe; printMe = document.getElementById(‘print-me’); printMe.addEventListener(‘click’, function () { window.print(); return false; }, false); })(); 6
  • 7.
    In all othercases, simply don’t pollute. 7
  • 8.
    Rules for ResponsibleGlobals Namespace everything. Only one global per library. Only one global per application. 8
  • 9.
    Good libraries... When choosinga library, choose a responsible one. • jQuery w/compatibility mode is great • YUI is also a great choice 9
  • 10.
    Good applications... Keep itsimple: each app gets a global In most cases, a site == an app In other cases, a page == an app • searchResults • userProfile • shoppingCart 10
  • 11.
    Namespaces http://www.lovemikeg.com/blog/2010/01/20/responsible-javascript-namespaces/ 11
  • 12.
  • 13.
  • 14.
    Namespaces can get outof control. Fast. 14
  • 15.
    com.foo.utils.appManager .myApp.widgets .contactForm.validate(); 15
  • 16.
    Responsible Namespaces Use anamespace creator function Segregate application namespaces from library namespaces Organize libraries into component groups Organize applications into functional groups 16
  • 17.
    This might seemlike a good idea… var myNS = { … }; …until you have multiple modules in myNS. 17
  • 18.
    How do youdo this reliably? myNS.myModule = { … }; 18
  • 19.
    How do youdo this reliably? var myNS = window.myNS || {}; myNS.myModule = {}; 19
  • 20.
    This is abetter idea: foo.namespace(‘myNS.myModule’); 20
  • 21.
    Applications vs. Libraries Applicationsare living, breathing structures which must be accepting to change both internally and externally. Libraries are shared dependencies and must be be organized in a stable structure so as to minimize the need for change at all. 21
  • 22.
    In other words... Youapplication will be a self-contained entity which is made up of lots of smaller components. • Don’t be strict and rigid with your app namespaces. • References to other apps are common, keep app namespaces shallow. 22
  • 23.
    Prototypes http://www.lovemikeg.com/blog/2010/01/21/responsible-javascript-prototype-modification/ 23
  • 24.
  • 25.
    “With great powerthere must also come… great responsibility!” — Amazing Fantasy #15 (The first Spider-Man story) 25
  • 26.
    “Yeah, but Iwant convenience.” Array.prototype.each = function (callback) { for (var i = 0, l = this.length; i < l; i++) { callback(this[i], i); } }; 26
  • 27.
    Think it through… Isit proper to cast your dependencies on the language itself? How/Where is this documented? Is it obvious to your team? Are there any other unintended consequences? 27
  • 28.
    How many membersin foo? Object.prototype.count = function () { var count = 0; for (var i in this) count++; return count; }; console.log( {'foo':12345}.count() ); 28
  • 29.
    Go ahead. Sayit. “But you should be using Object.hasOwnProperty.” • Yeah but does anyone actually do that? • Do you feel comfortable assuming that all future developers on your project will know that? 29
  • 30.
    A better optionis to simply extend. 30
  • 31.
    var MyArray =function () {}; MyArray.prototype = new Array; 31
  • 32.
    Factories http://www.lovemikeg.com/blog/2010/01/22/responsible-javascript-using-factories/ 32
  • 33.
  • 34.
    Factories manage complexity. …andanything that reduces complexity should be considered a best practice right? Factories can also: • Make your code safer • Make your code faster 34
  • 35.
    Factories are asafety measure. var Person = function (name, location) { this.name = name; this.location = location; }; var mike = new Person('Mike G.', 'NYC'); var alex = Person('Alex H.', 'NYC'); // oops! 35
  • 36.
    Constructors are simply broken. Forgettingthe new keyword can be disastrous. Best case scenario, a few globals spill out. Worst case scenario, your app stops working. 36
  • 37.
    Problem solved. Person.factory =function (name, location) { return new Person(name, location); } var mike = new Person.factory('Mike G.', 'NYC'); var alex = Person.factory('Alex H.', 'NYC'); 37
  • 38.
    this http://www.lovemikeg.com/blog/2010/01/23/responsible-javascript-using-this/ 38
  • 39.
    this hasan identity crisis. 39
  • 40.
    var foo ={ ‘bar’ : 12345, ‘getBar’ : function () { return this.bar; }, ‘onclickCallback’ : function () { window.open(this.href); return false; }, ‘wtf’ : function () { return { ‘hello’ : ‘world’, ‘sayHi’ : function () { return this.hello; } }; } }; 40
  • 41.
    this is ambiguous Itrefers to the object in which its defined. Unless: • It’s copied (referenced) to another object • It’s used as an event handler (sometimes). • You .call or .apply it. 41
  • 42.
    Best practices Know yournamespace. Be explicit. Fix your events.You can never be too sure. Keep your event handlers in a separate object. Document all irregularities (including event handlers). 42
  • 43.
  • 44.
    ++ and --have a bad reputation… to some. 44
  • 45.
    “The ++ (increment)and -- (decrement) operators have been known to contribute to bad code by encouraging excessive trickiness. They are second only to faulty architecture in enabling to viruses and other security menaces.” —Douglas Crockford http://www.jslint.com/lint.html#inc 45
  • 46.
    Trickiness like... var a= 1; var b = 2; var c = 3; console.log(a++ + b == c); console.log(a + ++b == c); console.log(a + + + b == c); console.log(a, b, c); 46
  • 47.
    Suggestions Don’t write trickycode like that. • Probably your best bet ;) Don’t use incrementors/decrementors • There’s nothing wrong with += 1 47
  • 48.
  • 49.
    switch can breakif you don’t break. 49
  • 50.
    function dateSuffix(date) { switch (date){ case (1) : case (21) : case (31): dt = "st"; break; case (2) : case (22): dt = "nd"; break; case (3) : case (23): dt = "rd"; break; default: dt = "th"; } return date + suffix; } 50
  • 51.
    … is thesame as… 51
  • 52.
    function betterDateSuffix (date){ if (date === 1 || date === 21 || date === 31) { return date + 'st'; } else if (date === 2 || date === 22) { return date + 'nd'; } else if (date === 3 || date === 23) { return date + rd; } else { return date + 'th'; } return date + suffix; } 52
  • 53.
  • 54.
    function yetAnotherDateSuffix (date) { var suffixMap = { 'st' : (date === 1 || date === 21 || date === 31), 'nd' : (date === 2 || date === 22), 'rd' : (date === 3 || date === 23), 'th' : true }; for (var suffix in suffixMap) { if (suffixMap[suffix]) { return date + suffix; } } } 54
  • 55.
    Which is better? Dependson your team’s coding standards. I suggest: • The one which is easiest to understand. • The one which is easiest to change. (I like the third option, personally.) 55
  • 56.
  • 57.
    Equality isn’t aseasy as you think. 57
  • 58.
    Take your bestguess console.log(false == -1); console.log(false == -0); console.log(false == 0); console.log(false == []); console.log(false == ""); console.log(false == "0"); console.log(false == null); console.log(false == undefined); console.log(false == null); 58
  • 59.
    Take your bestguess console.log(false == -1); // false console.log(false == -0); // true console.log(false == 0); // true console.log(false == []); // true console.log(false == ""); // true console.log(false == "0"); // true console.log(false == null); // false console.log(false == undefined); // false console.log(false == null); // false 59
  • 60.
    Just use ===or !== Your code will be less ambiguous Your code will run faster • No need to convert types 60
  • 61.
    $ 61
  • 62.
  • 63.
    The problem, isthat everyone loves $. Brought to you by Prototype Made famous by jQuery But what happens if you include jQuery and Prototype on the same page? 63
  • 64.
    The Specs say... “$is reserved for implementations” • Whatever that means. 64
  • 65.
    Fact: $ isperfectly valid. 65
  • 66.
    “Just don’t dothat.” Yeah. Easier said than done. • Try talking your client its better to rewrite the widget written in another library • They like their $$ too. 66
  • 67.
    Just don’t beirresponsible. Give your devs a choice to use it or not Never write applications that assume $ Always assume control over $ 67
  • 68.
    There is hope. jQueryhas compatability mode. • Please use it. • Develop your apps as if you’re writing a plugin… var myApp = (function ($) { // Your code goes here. })(window.jQuery); YUI is a nice choice too ;) 68
  • 69.