JavaScript pitfalls

26
SOME JAVASCRIPT PITFALLS by Claudio Cicali (Sponsorpay) @gmail.com // @caludio

description

 

Transcript of JavaScript pitfalls

Page 1: JavaScript pitfalls

SOME JAVASCRIPTPITFALLS

by Claudio Cicali (Sponsorpay)

@gmail.com // @caludio

Page 2: JavaScript pitfalls

DISCLAIMERThe following examples are meant to run

inside the global scope

I'm also not a "always use the === test operator" kind of guy [1]

[1] long time PHP developer

Page 3: JavaScript pitfalls

DECLARATIONS AND EXPRESSIONS// A variable declarationvar A;

// An assignment expression (definition / initialization)A = 0;

// Declaration and definitionvar A = 0;

Page 4: JavaScript pitfalls

DON'T TOUCH UNDECLARED VARIABLES// Reference error: A is not defined (just for the harmless test)if ( A == undefined ) { console.log("Hello");}

// This will fail as well (very common mistake!)if ( !A ) { console.log("Hello");}

Page 5: JavaScript pitfalls

DON'T TOUCH UNDECLARED VARIABLES// To test if a variable is declared, always* use the typeof operatorif ( typeof A == "undefined" ) { console.log("hello");}

// * Unless you are testing an object property

var A;

// No errorsif ( A == undefined ) { console.log( A ); // "undefined"}

Page 6: JavaScript pitfalls

UNDEFINED PROPERTIES

any object property is declared within the object itself

var myObj = { };

// No errors (we can skip the typeof test) if ( myObj.A == undefined ) { console.log( typeof myObj.A ); // undefined }

Page 7: JavaScript pitfalls

VARIABLE HOISTING// No errorsif (A === 0) { console.log("Have a Coke");}

// In the same scope, variables can be declared *after* being usedvar A = 0;

// The declaration is "hoisted" at the very top of the scope+--> var A;|| // The test fails nonetheless| if (A === 0) {| console.log("Have a Coke");| }|| // The definition is NOT hoisted (thus, no Coke for us)+--- A = 0;

Page 8: JavaScript pitfalls

VARIABLE HOISTING// Error (declaration out of scope, no "hoisting")if (A) { console.log("hello");}

function foobar() { var A = 0;}

var A = 42;

function foobar() { console.log( A ); // Can you guess?

var A = 0; // Declaration hoisted, NOT the assignment}

foobar();

Page 9: JavaScript pitfalls

VARIABLE HOISTINGvar A = 42;

function foobar() { console.log( A ); // 42

// var A = 0;}

foobar();

Page 10: JavaScript pitfalls

FUNCTION DECLARATIONS ANDEXPRESSIONS

// This a function declaration (a name, no assignment)function FOOBAR() {}

// This is a function expression (assignment)var FOOBAR = function() {};

// This is still a function expression (a "named" one)var FOOBAR = function something() { // The "something" symbol can be used only in this scope};

Page 11: JavaScript pitfalls

FUNCTION DECLARATIONS ANDEXPRESSIONS

(function something() { // Recursion without using arguments.callee (deprecated) something();})();

// This is wrong (syntax error)function() {};

// But those are - again - valid expressions-function() {};+function() {};!function() {};0,function() {};(function() {});

Page 12: JavaScript pitfalls

FUNCTION DECLARATION HOISTING// Available (declaration has been hoisted)foo(); // "One"

// Function declaration (w/o this we'd get an error)function foo() { console.log('One');}

// Function expression (evaluated at run-time, not hoisted)var foo = function() { console.log("Two");}

// Will log "Two"foo();

Page 13: JavaScript pitfalls

HIDDEN GLOBALSfunction sillyOperation() {

var A = B = 0;

// Will be parsed as follows var A; A = 0; B = 0;

// thus creating a global variable B

}

Page 14: JavaScript pitfalls

HIDDEN GLOBALS// Will create a global Pfor (P in myObject) { console.log(P);}

// Always use varfor (var P in myObject) { console.log(P);}

Page 15: JavaScript pitfalls

ARRAYS: DO NOT USE AS DICTIONARIES!var A = [];

// There are no "associative arrays", in JavaScript

A['key1'] = 100; // The same as A.key1 = 100;A['key2'] = 200; // The same as A.key2 = 200;

console.log(A.length); // 0, still 0

// Use plain objects insteadvar A = {};

A['key1'] = 100;A['key2'] = 200;

console.log( Object.keys(A).length ); // 2 (ES5)

Page 16: JavaScript pitfalls

ARRAYS: THEY ARE NOT SPARSEvar A = [];

A[999] = 47;

console.log( A.length ); // 1000 (with 999 undefined values)

Page 17: JavaScript pitfalls

USE USE STRICT// Switch on "strict mode" with just an harmless string

"use strict";

// This, now illegal, assignment of an undefined variable will // throw an error instead of implicitely declaring a (global) variable

A = 49;

"use strict";

// Duped properties: this will now throw an errorvar A = { P1: "foo", P2: "bar", P1: "zot" };

Page 18: JavaScript pitfalls

USE USE STRICT"use strict";

// "with" does not exist anymore (syntax error)with (object) {

}

"use strict";

function foobar() { console.log( this ); // undefined}

Page 19: JavaScript pitfalls

USE USE STRICT"use strict";// "Inner functions" are not permitted really ANYWHEREif (true) { function innerFoobar() { } // syntax error}// In not strict-mode, you could write a monstruosity likeif (true) { function innerFoobar() { console.log(1); }} else { function innerFoobar() { console.log(2); }}innerFoobar(); // Can you guess the result?

function outerFoobar() { function innerFoobar() { } // Still permitted}

Page 20: JavaScript pitfalls

A NOTE OF WARNING ON USE STRICTStrict mode applies to the context it is used

Scrict mode changes semantics: be sure to apply it only oncode you control

<script>// global context"use strict";...</script>

<script src="legacy_lib.js"></script>

// Now the code inside legacy_lib will run in strict mode.// Don't do that.

Page 21: JavaScript pitfalls

( PARENTHESIS )// Let's get the integer part of this numbervar A = 3.14;

// The usual wayconsole.log( Math.floor( A ) );

// Sligthly faster, compresses betterconsole.log( 0|A );

Page 22: JavaScript pitfalls

( PARENTHESIS )// What I "discovered", using this techniquevar A = 3.14;var B = 3.14;

console.log( 0|A === 0|B ); // true? No, "3" (true-ish)

// My bug was exploited by something likevar A = 3.14;var B = 13.14;

console.log( 0|A === 0|B ); // false? No, "13", still true-ish

Page 23: JavaScript pitfalls

( PARENTHESIS )What happened then?

Operators precedence, of course.

0|A === 0|B // is 0|false|13.14

// When unsure, use parenthesis

var A = 3.14;var B = 13.14;

console.log( (0|A) === (0|B) ); // false? Yes!

Page 24: JavaScript pitfalls

IIFE ARE LOVELY. USE THEM.Immediately-Invoked Function Expression ("iffy")

;(function(w, $, undefined) {

// This is your courtyard: here you can play safe and sound

// Better compression // Slightly faster when accessing global objects (which are local) // Not even one single global symbol declared

"use strict"; // Strict mode for your code only

})(window, jQuery);

Page 25: JavaScript pitfalls

IIFE ARE LOVELY. USE THEM.More than one style

Technically, we need to coerce the function to be anexpression, not a declaration

Other "formats" exist, but you betterstick with those for convention sake.

// Doug Crockford recommends this one( function() { }() );

// This one will work as well( function() {} )();

Page 26: JavaScript pitfalls

THANK YOUClaudio Cicali, @caludio on twitter

Created with Reveal.js