This document provides an overview of best practices for writing responsible JavaScript code. It discusses topics like avoiding globals, using namespaces, modifying prototypes responsibly, factories for object creation, properly handling the this keyword, best practices for switch statements, equality comparisons, and the use of $ in libraries and applications. The document emphasizes writing clear, understandable code, avoiding ambiguity and potential bugs, and being considerate of other code on the page.
8. Rules for Responsible Globals
Namespace everything.
Only one global per library.
Only one global per application.
8
9. Good libraries...
When choosing a library, choose a responsible
one.
• jQuery w/compatibility mode is great
• YUI is also a great choice
9
10. 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
16. Responsible Namespaces
Use a namespace creator function
Segregate application namespaces from library
namespaces
Organize libraries into component groups
Organize applications into functional groups
16
17. This might seem like a good
idea…
var myNS = { … };
…until you have multiple
modules in myNS.
17
18. How do you do this reliably?
myNS.myModule = { … };
18
19. How do you do this reliably?
var myNS = window.myNS || {};
myNS.myModule = {};
19
20. This is a better idea:
foo.namespace(‘myNS.myModule’);
20
21. 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
22. 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
25. “With great power there must
also come… great responsibility!”
— Amazing Fantasy #15 (The first Spider-Man story)
25
26. “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
27. 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
28. 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
29. 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
34. 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
35. 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
36. 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
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
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
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
42. 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
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 tricky code like that.
• Probably your best bet ;)
Don’t use incrementors/decrementors
• There’s nothing wrong with += 1
47
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?
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
63. 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
64. The Specs say...
“$ is reserved for implementations”
• Whatever that means.
64
66. “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
67. 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
68. 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