JavaScript
good practices
and tips and tricks
Damian Wielgosik
[Link]
[Link]
[Link]/varjs
remember that performance tips
change over the time as JVM
evolves
make yourself familiar with
ECMAScript
ECMAScript
sometimes it’s difficult...
... to speak in a human language
... znaleźć ludzki
Dmitry język
Soshnikov
your personal ECMAScript teacher
lint your code, hurt your feelings
[Link]
[Link]
/*jslint sloppy: true, vars: true, white: true, plusplus: true,
newcap: true */
(function() {
// ...
})();
mount your linting tool to the
text editor/IDE you use
it’s a result of cmd+L in TextMate
go TDD when it’s possible
try [Link]
([Link]/)
(function() {
if (typeof require == "function" && typeof module ==
"object") {
buster = require("buster");
require("../models/[Link]");
}
var assert = [Link];
var factory;
[Link]("ArticleFactory", {
setUp: function () {
factory = new [Link]();
},
"createArticle should not return null": function () {
var article = [Link](1, "Foobar",
"bla bla", "12/12/2012","12:12",
[Link], { addArticle: function()
{}}, {}, {});
[Link](article);
},
});
})();
there is a lot of unit testing
libraries, choose the best
there are great presentations too
[Link]/szafranek/practical-guide-to-unit-
testing
use native language parts for
creating objects and arrays
var arr = []; // not new Array
var obj = {}; // not new Object
use self-invoking functions not
to pollute outer scope
(function() {
// do stuff here
})();
use self-invoking functions not
to pollute outer scope
(function() {
var privateVar = 1;
})();
[Link](privateVar); // undefined
define variables at the top of the
scope
var fn = function() {
var news = [],
timer,
foobar;
};
use === everywhere
0 === ""; // false
0 == ""; // true
do not iterate over an array with
for in loop
[Link] = function() {
// ...
};
var arr = [1, 2, 3];
for (var i in arr) {
[Link](i); // contains
}
add to an array using push
var arr = [1];
[Link](2);
arr; // [1,2]
you can store a global object to
avoid mistakes with this
(function() {
var global = this;
[Link](global === window); // true
})();
global compatible with
ECMAScript 5 and „use strict”
"use strict";
var global = Function('return this')();
cache native functions to protect
them
(function() {
var isArray = [Link];
})();
be careful with this
var obj = {
foo : function() {
return [Link];
},
myVariable : 1
};
var fn = [Link];
fn(); // undefined
be careful with this - don’t forget
about call/apply
var obj = {
foo : function() {
return [Link];
},
myVariable : 1
};
var fn = [Link];
[Link](obj); // 1
be careful with this - don’t forget
about bind
var obj = {
foo : function() {
return [Link];
},
myVariable : 1
};
var fn = [Link](obj);
fn(obj); // 1
not every browser supports
[Link]
not every browser supports
[Link] - but you can
polyfill it!
[Link] polyfill
if (![Link]) {
[Link] = function (oThis) {
if (typeof this !== "function") {
// closest thing possible to the ECMAScript 5 internal IsCallable function
throw new TypeError("[Link] - what is trying to be bound is
not callable");
}
var aArgs = [Link](arguments, 1),
fToBind = this,
fNOP = function () {},
fBound = function () {
return [Link](this instanceof fNOP
? this
: oThis,
[Link]([Link](arguments)));
};
[Link] = [Link];
[Link] = new fNOP();
return fBound;
};
}
for loop is not slower than while
[Link]/for-loop-research
using indexes with localStorage
is faster than getItem in some
browsers
[Link]/localstorage-science
using indexes with localStorage
is faster than getItem in some
browsers
var key = 1;
localStorage[key]; // faster
[Link](key); // slower
native forEach is not faster than
classic loops
var arr = [1, 2, 3, 4, 5];
[Link](function() {}); // slower
for (var i = 0, ilen = [Link]; i < ilen; i++) {}; // faster
[Link]/for-vs-array-foreach
use requestAnimationFrame if you deal with
heavy proccesses like DOM manipulation
(function() {
var requestAnimationFrame = [Link] ||
[Link] || [Link] ||
[Link] || function(fn) { [Link](fn,
16); };
[Link] = requestAnimationFrame;
var start = [Link]().
var elements = 0;
var step = function() {
var house = [Link]("div");
[Link]("house");
[Link](building);
elements++;
if (elements < 10000) {
requestAnimationFrame(step);
}
}
requestAnimationFrame(step);
})();
do not create too many functions
- that costs memory
[Link](function() {
makeThings();
}, 16);
no!
var frame = function() {
makeThings();
};
[Link](frame, 16);
yes!
functions are objects
var fn = function() {};
[Link] = 1;
[Link]; // 1
functions are objects, so they
help cache
var getSin = function(num) {
if (getSin[num]) {
return getSin[num];
} else {
return getSin[num] = [Link](num);
}
};
more crossbrowser isArray?
(function() {
var toString = [Link];
var isArray = [Link] || function(arr) { return [Link]
(arr) === "[object Array]"; };
})();
clear arrays using length for
memory performance
var arr = [1, 2, 3, 4, 5];
[Link] = 0; // instead of arr = [];
max number in an array?
var arr = [1, 2, 3, 4, 5];
[Link](Math, arr);
use ”in” to check if the property
is defined in the object
var obj = {
foobar : ""
};
'foobar' in obj; // true
'barbar' in obj; // false
!![Link]; // false
use typeof to check variable
types
var num = 2;
if (typeof num === "number") {
// we have a number
}
use typeof to check if you can
fire a function
var fn = function() {};
if (typeof fn === "function") {
fn();
}
typeof RegExp
typeof RegExp === "function"; // true
typeof /\d+/g; // "object"
you don’t need jQuery just to get
some nodes
var news = [Link]("[Link]"); // finds all the elements
var news = [Link]("[Link]"); // finds the first element
you don’t need regular
expressions to work with class
names
[Link]("foo"); // <body class="foo">
[Link]("foo"); // true
[Link]("foo"); // <body>
[Link]("foo"); // <body class="foo">
[Link]("foo"); // <body>
build your view templates with
innerHTML
var html = '<ul class="news">' +
'<li>' +
'<h1>Something</h1>' +
'<p>Text</p>' +
'</li>' +
'</ul>';
[Link] = html;
var newsList = [Link](".news");
make use of datasets
<div data-id="123" data-type="news"></div>
[Link]; // "123"
[Link]; // "news"
did you know about
[Link]?
<div id="foo" class="bar">This is the element!</div>
<script type="text/javascript">
var el = [Link]("foo");
if ([Link]("[Link]")) {
alert("Match!");
}
</script> // thanks to MDN
[Link] if
[Link] is not enough
<style>
#elem-container{
position: absolute;
left: 100px;
top: 200px;
height: 100px;
}
</style>
<div id="elem-container">dummy</div>
<div id="output"></div>
<script>
function getTheStyle(){
var elem = [Link]("elem-container");
var theCSSprop = [Link](elem,null).getPropertyValue("height");
[Link]("output").innerHTML = theCSSprop;
}
getTheStyle();
</script>
innerHTML is not the fastest
way to check if node is empty
if ([Link] === "") {} // slower
if ([Link] === 0) {} // faster
don’t extend DOM nodes with
custom properties to avoid
memory leaks
var div = [Link]("div");
[Link] = function() {};
add events using
addEventListener
[Link]("click", function() {
alert("Boom!");
}, false);
do not forget to prevent form
submitting when dealing with
web app forms that are sent e.g.
by AJAX
[Link]("submit", function(e) {
[Link]();
}, false);
Performance?
var start = +new Date();
for (var i = 0; i < 100000; i++);
[Link]("Result is: ", +new Date() - start);
Better?
[Link]("My test");
for (var i = 0; i < 100000; i++);
[Link]("My test");
Still better?
[Link]("My test");
runApp();
[Link]("My test");
The best?
[Link]
[Link]
jsperf measures operations per
second!
See also [Link]
do not optimize prematurely!
JavaScript !== Java
do not optimize prematurely!
[Link]/photos/paulmartincampbell/3583176306/sizes/o/in/photostream/
forget about your old habits!
do not port bad solutions to JavaScript!
otherwise they’re gonna find
you! ;-)
[Link]
function calls cost time!
use JS asynchronously when needed
var arr = [ function() { [Link]("A"); },
function() { throw new Error("boom!"); },
function() { [Link]("B"); },
function() { [Link]("C"); }
];
for (var i = 0, ilen = [Link]; i < ilen; i++) {
arr[i]();
}
oops?
var arr = [ function() { [Link]("A"); },
function() { throw new Error("boom!"); },
function() { [Link]("B"); },
function() { [Link]("C"); }
];
for (var i = 0, ilen = [Link]; i < ilen; i++) {
[Link](arr[i], 0);
}
timers can be useful with AJAX requests
var throttle = function(fn, delay) {
var timer = null;
return function () {
var context = this;
var args = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
[Link](context, args);
}, delay);
};
};
$('[Link]').keypress(throttle(function (event) {
// do the Ajax request
}, 250));
[Link]
parseInt(„09”) === 0
JS thinks „09” is an octal number
because it starts with 0
parseInt(„09”, 10) === 9
However,
parseFloat(„09”) === 9
However,
parseFloat(„09”) === 9
[Link]("div")
returns a NodeList
not an array
var nodes = [Link]("div");
nodes = [].[Link](nodes);
However:
„Whether the slice function can be applied successfully to a host object is
implementation-dependent.” - ECMAScript
mobile?
Use [Link](0, 1) to get rid of the browser address bar
on iOS!
/mobile/[Link]([Link]) && ![Link] && setTimeout
(function () {
if (!pageYOffset) [Link](0, 1);
}, 1000);
thanks to amazing work by Remy Sharp
[Link]
iphone-url-bar/
Mobile debugging?
Aardwolf - mobile
debugging made easy
Yes, we all know Firebug and Web Inspector
Memory stats?
WebKit Inspector
Memory?
Memory leaks?
Memory leak checker
sIEeve
Performance?
[Link]/jsrosman/
Memory leaks?
[Link]/~dbaron/leak-screencasts/
general thoughts
Get rid of jQuery if it’s not neccessary -
there is [Link]
Hunt on new stuff!
[Link] might be a good start!
Visit JSNews on Facebook for more awesomeness
[Link]
or attend [Link] meetups
Poznan, Warsaw, Wroclaw, Cracow
[Link]
but first of all, be smart and listen to smart people -
there is a lot on the web