responsible javascript

69
Responsible JavaScript Refresh NYC — January 2010 1

Upload: michael-girouard

Post on 11-May-2015

1.618 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: Responsible JavaScript

Responsible JavaScriptRefresh NYC — January 2010

1

Page 2: Responsible JavaScript

Where should I get started?

• Globals

• Namespaces

• Prototypes

• Factories

• this

• Incrementing & Decrementing

• switch () {...}

• Equality

• $

2

Page 4: Responsible JavaScript

Globals have a bad reputation.

4

Page 5: Responsible JavaScript

Where possible, just avoid them.

5

Page 6: Responsible JavaScript

(function () {

var printMe;

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

})();

6

Page 7: Responsible JavaScript

In all other cases, simply don’t pollute.

7

Page 8: Responsible JavaScript

Rules for Responsible Globals

Namespace everything.

Only one global per library.

Only one global per application.

8

Page 9: Responsible JavaScript

Good libraries...

When choosing a library, choose a responsible one.

• jQuery w/compatibility mode is great

• YUI is also a great choice

9

Page 10: Responsible JavaScript

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

Page 12: Responsible JavaScript

Namespaces are a really good idea.

12

Page 13: Responsible JavaScript

jQuery.ajax(…)

13

Page 14: Responsible JavaScript

Namespaces can get out of control. Fast.

14

Page 15: Responsible JavaScript

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

15

Page 16: Responsible JavaScript

Responsible Namespaces

Use a namespace creator function

Segregate application namespaces from library namespaces

Organize libraries into component groups

Organize applications into functional groups

16

Page 17: Responsible JavaScript

This might seem like a good idea…

var myNS = { … };

…until you have multiple modules in myNS.

17

Page 18: Responsible JavaScript

How do you do this reliably?

myNS.myModule = { … };

18

Page 19: Responsible JavaScript

How do you do this reliably?

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

19

Page 20: Responsible JavaScript

This is a better idea:

foo.namespace(‘myNS.myModule’);

20

Page 21: Responsible JavaScript

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

Page 22: Responsible JavaScript

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

Page 24: Responsible JavaScript

Prototypes are powerful. Really powerful.

24

Page 25: Responsible JavaScript

“With great power there must also come… great responsibility!”

— Amazing Fantasy #15 (The first Spider-Man story)

25

Page 26: Responsible JavaScript

“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

Page 27: Responsible JavaScript

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

Page 28: Responsible JavaScript

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

Page 29: Responsible JavaScript

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

Page 30: Responsible JavaScript

A better option is to simply extend.

30

Page 31: Responsible JavaScript

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

31

Page 33: Responsible JavaScript

Factories are your friends.

33

Page 34: Responsible JavaScript

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

Page 35: Responsible JavaScript

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

Page 36: Responsible JavaScript

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

Page 37: Responsible JavaScript

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

Page 39: Responsible JavaScript

this has an identity crisis.

39

Page 40: Responsible JavaScript

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

Page 41: Responsible JavaScript

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

Page 42: Responsible JavaScript

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

Page 43: Responsible JavaScript

Incrementing & Decrementing

43

Page 44: Responsible JavaScript

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

44

Page 45: Responsible JavaScript

“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 Crockfordhttp://www.jslint.com/lint.html#inc

45

Page 46: Responsible JavaScript

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

Page 47: Responsible JavaScript

Suggestions

Don’t write tricky code like that.

• Probably your best bet ;)

Don’t use incrementors/decrementors

• There’s nothing wrong with += 1

47

Page 48: Responsible JavaScript

switch () {...}

48

Page 49: Responsible JavaScript

switch can break if you don’t break.

49

Page 50: Responsible JavaScript

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

Page 51: Responsible JavaScript

… is the same as…

51

Page 52: Responsible JavaScript

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

Page 53: Responsible JavaScript

and …

53

Page 54: Responsible JavaScript

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

Page 55: Responsible JavaScript

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

Page 56: Responsible JavaScript

Equality

56

Page 57: Responsible JavaScript

Equality isn’t as easy as you think.

57

Page 58: Responsible JavaScript

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

Page 59: Responsible JavaScript

Take your best guess

console.log(false == -1); // falseconsole.log(false == -0); // trueconsole.log(false == 0); // trueconsole.log(false == []); // trueconsole.log(false == ""); // trueconsole.log(false == "0"); // trueconsole.log(false == null); // falseconsole.log(false == undefined); // falseconsole.log(false == null); // false

59

Page 60: Responsible JavaScript

Just use === or !==

Your code will be less ambiguous

Your code will run faster

• No need to convert types

60

Page 61: Responsible JavaScript

$

61

Page 62: Responsible JavaScript

Developers love $.

62

Page 63: Responsible JavaScript

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

Page 64: Responsible JavaScript

The Specs say...

“$ is reserved for implementations”

• Whatever that means.

64

Page 65: Responsible JavaScript

Fact: $ is perfectly valid.

65

Page 66: Responsible JavaScript

“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

Page 67: Responsible JavaScript

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

Page 68: Responsible JavaScript

There is hope.

jQuery has compatability mode.

• Please use it.

• Develop your apps as if you’re writing a plugin…

YUI is a nice choice too ;)

var myApp = (function ($) { // Your code goes here.})(window.jQuery);

68