Download - JavaScript Proven Practises
JavaScriptProven Practices
20 June 2012
Agenda
Cover proven practices about how to write better JavaScript
Lots of slides (50+) but a lot are code we will talk about and see what is right & what is wrong
Assumption: You can read JavaScript (or fake it)
JavaScript is a sloppy language, but inside it there is an elegant, better language.
Douglas Crockford - Jslint.com
Situation 11. var i=0;2. function demo(){3. for (i=0; i<10; i++){ 4. // do stuff5. } 6. }
7. demo();8. // what is i?
code
10
output
Situation 1 cont.1. function demo(){2. i = 50;3. }
4. demo();5. // what is i?
code
50
output
Always use varVariables have scope
GlobalFunction
Using var helps keep the scope straight
Always use var - fixes1. var i=0;
2. function demo(){3. var i = 0;4. for (i=0; i<10; i++){ 5. print("demo");6. } 7. }
8. demo();9. // what is i?
Always use var - fixes1. var i =0;
2. function demo(){3. for (var i=0; i<10; i++){ 4. print("demo");5. } 6. }
7. demo();8. // what is i?
Situation 2
1. function setspan(num, text)2. {3. eval("myspan" + num + ".innerText = '" + text + "'");4. }
code
//syntax error
output
1. myspan1.innerText = 'it ain't what you do, it's the way thacha do it';
data
Situation 2 cont.
1. eval("var a = 'awesome';");2. print(a);
code
'awesome'
output
Avoid evaleval is hard to get right and there are many many situations out of your control you need solve
eval runs code – so you are saying you trust the user to write code
Modern browsers pre-compile JavaScript, eval doesn’t benefit from this!
Situation 3
1. function doSomething(someValue){ 2. //... 3. } 4. 5. setTimeout("doSomething('3 seconds elapsed. Time is up.');", 3000);
code
1. var sum = new Function('op1', 'op2', 'return op1 + op2;'); 2. var result = sum(10, 20); // ==> 30
code
Avoid eval part 2eval can appear in sneaky locations in JavaScript
Timers – SetTimeout & SetIntervalFunction contstructors
Avoid Eval Part 2 Fixed
1. setTimeout(function(){ 2. doSomething('3 seconds elapsed. Time is up.'); 3. }, 3000);
1. function sum(op1, op2){2. return op1 + op2;3. }
Situation 41. var total = variable1 + variable2;2. print(total);
code
1. 12
output
1. var variable1 = "1";2. var variable2 = "2";
data
1. var variable1 = document.elements["inputA"].value;
I’d never be so stupid to add strings?
Situation 41. var total = parseInt(variable1) + parseInt(variable2);2. print(total);
code
3
output
1. var variable1 = "1";2. var variable2 = "2";
data
1. var variable1 = "064";2. var variable2 = "032";
data
78
output
64 base 8 = 52 base 1032 base 8 = 26 base 1052 + 26 = 78
Unary OperatorJavaScript has one type for numbers
Other primitives: Object, string & boolean, RegExp, Math, Array, Date, Error, NativeError (mostly)
parseInt & parseFloat require you to set the numeric base the number is in – else it will try and guess
Unary Operator(+<variable>) is the right way to get an number
Even though braces are optional - you should always have them, else it is hard to work out what is addition and what is unary
Unary Operator Fixed1. var total = (+variable1) + (+variable2);2. print(total);
code
3
output
96
output
1. var variable1 = "1";2. var variable2 = "2";
data
1. var variable1 = "064";2. var variable2 = "032";
data
Unary Operator vs. parseInt
1. parseInt("567Gb");
code
567
output
1. +"567Gb";
code
NaN
output
Situation 5
1. function validate (idNumber) {2. var year = getYear(idNumber);3. // omitted4. }5. 6. function getYear(idNumber) {7. // omitted8. }
NamespacesGroup things into namespaces, so that they are properly scoped.
Expose only what you need to expose.
There are at least 5 different ways to do namespaces – pick one as a team. I’m going to show you my favourite next – the Self-Executing Anonymous Function Public & Private.
Namespaces Fixed1. (function (idNumbers, undefined) {2. 3. idNumbers.validate = function (idNumber) {4. var year = getYear(idNumber);5. // omitted6. }7. 8. function getYear(idNumber) {9. // omitted10. }
11. }(window.idNumbers = window.idNumbers || {}));
Namespaces Fixed1. idNumbers.validate(""); // works
2. idNumbers.getYear(""); // undefined
Namespaces Fixed
1. (function (idNumbers, $, undefined) {2. 3. // omitted
4. }(window.idNumbers = window.idNumbers || {}, jQuery));
Separation of concernsTaking namespaces further – practise separation of concerns
Put JavaScript into separate files – do not inline in the HTML file.Build as much of your JavaScript do it is not tied to HTML or CSS Let HTML do what it is good at (organisation of content), CSS do what it is good at (presentation style) & JavaScript do what it is good at
1. itemX.color = "#fff";2. itemX.font-family = "Consolas";
bad
1. itemX.style = "codeBlock";
good
Situation 61. with (document.forms["mainForm"].elements) {2. input1.value = "junk";3. input2.value = "junk";4. }
code
1. <html>2. <body>3. <form id="mainForm">4. <input id="input1" type="text">5. <input id="input2" type="text">6. </form>7. </body>8. </html>
data
Situation 6 cont.1. with (document.forms["mainForm"].elements) {2. input1.value = "junk";3. input2.value = "junk";4. }
code
1. <html>2. <body>3. <form id="mainForm">4. <input id="input1" type="text">
5. </form>6. </body>7. </html>
data
Situation 6 cont.1. var input2;2. with (document.forms["mainForm"].elements) {3. input1.value = "junk";4. input2.value = "junk";5. }
code
1. <html>2. <body>3. <form id="mainForm">4. <input id="input1" type="text">5. </form>6. </body>7. </html>
data
Avoid WithNo way to really know who/what will be changed
Avoid with - Fixed
1. var o = document.forms["mainForm"].elements;2. o.input1.value = "junk";3. o.input2.value = "junk";
Situation 7
1. var o = new Object(); 2. o.name = 'Jeffrey'; 3. o.lastName = 'Way'; 4. o.someFunction = function() { 5. console.log(this.name); 6. }
code
Prefer object literalsPREFER
Allows for more flexibility, cleaner code (no constructors) & you don’t need to worry about constructor parameter ordering.
Prefer object literals - fixed1. var o = { 2. name : 'Jeffrey',3. lastName : 'Way',4. someFunction : function() { 5. console.log(this.name); 6. }7. };
1. var o = {};
Situation 8
1. var a = new Array(); 2. a[0] = "Robert";3. a[1] = "MacLean";
code
Prefer object literalsApplies to arrays just as well
Prefer object literals - fixed
1. var o = ["Robert", "MacLean"];
A common error in JavaScript programs is to use an object when an array is required or an array when an object is required. The rule is simple: when the property names are small sequential integers, you should use an array. Otherwise, use an object.
Douglas Crockford
Situation 9
1. var x = "123";2. var y = 123;
3. x == y;
code
1. true
output
Situation 9 cont.1. '' == '0'2. 0 == ''
3. false == 'false'4. false == '0'
5. false == undefined6. false == null7. null == undefined
8. ' \t\r\n' == 0
falsetrue
falsetrue
falsefalsetrue
true
Use === rather than ==== is equality=== is identityEquality checks type, if type differs will convert and then check valuesIdentity checks type, if type differs will return false
Use === rather than == - fixed1. "123" === 123; // false
2. '' === '0' // false3. 0 === '' // false
4. false === 'false' // false5. false === '0' // false
6. false === undefined // false7. false === null // false8. null === undefined // false
9. ' \t\r\n' === 0 // false
Situation 10
1. function x(){2. return 3. 64. }
5. x();
code
output
ALWAYS end with semicolonSemicolon is a statement separator in JavaScript
Putting semicolon’s in is optional – but then JavaScript will guess where the statements will be separated
Be consistent
ALWAYS end with semicolon - fixed
1. function x(){2. return 6;3. }
4. x();
code
6
output
Situation 11
1. var a = 1,2;2. var b = 1,2,3;3. var c = 99+1,99
code
2399
output
Avoid the comma operatorComma operator – not the comma separator in arrays – can lead to very tricky to understand code.
Unless you are 100% sure about it – don’t use it
Even when you are 100% sure – add comments for the rest of us
Comma Operator - Fixed1. var r = [], n = 0, a = 0, b = 1, next;
2. function nextFibonacci() { 3. next = a + b; 4. return b = (a = b, next);5. }
6. while(n++ < 10) {7. r.push(nextFibonacci());8. }
9. r; //[1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
Situation 121. foo = "awesome";
1. var foo = "awesome";2. delete foo;
1. var o = { foo: 123, foo: 456 };
1. function eval() { }
1. eval("var a = false;");2. print(a);
1. with
Turn Strict mode ONAll code runs in the strict context which makes your code more stable, finds more coding problems and raises more exceptions.Can define strict in a function
Turn Strict mode ONWhat does it do?
ECMAScript 3 deprecated methods raise exceptionsUnassigned variables throw exceptionsDelete throws exceptionsDuplicate properties throw exceptionsHijacking eval throws exceptionsEval code is sandboxedWith is goneMORE!!!
Full info: http://dmitrysoshnikov.com/ecmascript/es5-chapter-2-strict-mode/
Turn Strict mode ONFor this talk it helps with:
Situation 1 – always use var. Undeclared variables will syntax errorSituation 4 – parseInt defaults to decimal in strict mode
Your mileage may vary here: Chrome 19 does it wrong IE 10 does it right
Situation 6 – with. Always gives syntax error
Turn Strict mode ON - Fixed1. "use strict";
1. foo = "awesome"; // exception2. var bar = "awesome";3. delete bar; // exception4. var o = { foo: 123, foo: 456 }; // exception5. function eval() { } // exception6. eval("var a = false;");7. print(a); // undefined8. with //syntax error
1. function demo(){2. "use strict";3. // more4. }
Questions?
Next week: Tools
included will be tools that solve all these issues
Sourceshttp://www.javascripttoolbox.com/bestpractices
http://net.tutsplus.com/tutorials/javascript-ajax/24-javascript-best-practices-for-beginners/
http://stackoverflow.com/
http://www.crockford.com/
http://www.jslint.com/lint.html#options
http://enterprisejquery.com/2010/10/how-good-c-habits-can-encourage-bad-javascript-habits-part-1/