86
Tricks of the masters Expert JavaScript:

Expert JavaScript tricks of the masters

Embed Size (px)

DESCRIPTION

A presentation I gave at Dr. Dobbs India in the cities of Bangalore and Pune.

Citation preview

Page 1: Expert JavaScript  tricks of the masters

Tricks of the masters

Expert JavaScript:

Page 2: Expert JavaScript  tricks of the masters

JavaScript can be strange

Page 3: Expert JavaScript  tricks of the masters

JavaScript can be strange

• Syntactically similar to C++ and Java

“Java is to JavaScript as car is to carpet”• Prototypal inheritance

• Classless. Objects inherit from objects.

• Loosely typed• Type coercion. “Truthy” / “falsy” values.

• Objects are mutable

Page 4: Expert JavaScript  tricks of the masters

NodeLists

Page 5: Expert JavaScript  tricks of the masters

NodeLists

Get all the anchors in a page:

var anchors1 = document.getElementsByTagName('a');[<a href="#"> Item 1 </a>, <a href="#"> Item 2 </a>]

var anchors2 = document.querySelectorAll('a');[<a href="#"> Item 1 </a>, <a href="#"> Item 2 </a>]

Page 6: Expert JavaScript  tricks of the masters

NodeLists

User interaction causes more anchors to be added to the DOM.

Page 7: Expert JavaScript  tricks of the masters

NodeLists

One of our NodeLists is automatically updated:

console.log(anchors1);[<a href="#"> Item 1 </a>, <a href="#"> Item 2 </a>,<a href="#"> Item 3 </a>,<a href="#"> Item 4 </a>]

console.log(anchors2);[<a href="#"> Item 1 </a>, <a href="#"> Item 2 </a>]

Page 8: Expert JavaScript  tricks of the masters

Scope and Closures

Page 9: Expert JavaScript  tricks of the masters

Scope and Closures

JavaScript does not have block scope.

Sort of.

Page 10: Expert JavaScript  tricks of the masters

Scope and Closures

Variables are scoped to functions

var foo = "bar"; //global

function widget() {

var foo = "123"; //scoped to widget

}

Page 11: Expert JavaScript  tricks of the masters

Scope and Closures

Variables are scoped to functions

var message = 'Hello? Is anybody there?';

function helloWorld() {

var message = 'Hello, world!';

return message;

} // returns "Hello, world!"

Page 12: Expert JavaScript  tricks of the masters

Scope and Closures

Functions don't need to be named.

A common scoping technique is to use the Immediately-Invoked Function Expression (aka IIFE)

Page 13: Expert JavaScript  tricks of the masters

Scope and Closures

Immediately-Invoked Function Expression:

(function () {

var message = 'Hello, world!',

conferenceName = 'Dr. Dobbs India',

attendees = 'Awesome';

}());

Page 14: Expert JavaScript  tricks of the masters

Scope and Closures

Immediately-Invoked Function Expression:

(function ($) {

$('p'); //works

}(jQuery));

$('p'); //does not work

Page 15: Expert JavaScript  tricks of the masters

Scope and Closures

Functions also create closures.

Closure = Anything declared within a function is aware of anything else declared within that function.

Page 16: Expert JavaScript  tricks of the masters

Scope and Closures

Functions also create closures.

var public = 'Everybody sees this.';

function family() {

var father, mother;

function kids() {

var child1, child2;

}

}

Page 17: Expert JavaScript  tricks of the masters

Scope and Closures

Building a game leveraging closures:

var game = (function () {

var secret = 5;

return function (num) {

var total = secret * num;

console.log('You say ' + num + ', I say ' + total + '. What is my secret?');

};

}());

Page 18: Expert JavaScript  tricks of the masters

Scope and Closures

Building a game leveraging closures:

> game(5)

You say 5, I say 25. What is my secret?

> game(10)

You say 10, I say 50. What is my secret?

> secret

ReferenceError: secret is not defined

Page 19: Expert JavaScript  tricks of the masters

Scope and Closures

Block scope with let*

if (x) {

let myVar;

let yourVar = 123;

}

* Not yet available everywhere.

Page 20: Expert JavaScript  tricks of the masters

Scope and Closures

Block scope with let*

var myVar = 5;

let(myVar = 6) {

alert(myVar); // 6

}

alert(myVar); // 5

* Not yet available everywhere.

Page 21: Expert JavaScript  tricks of the masters

Memoization

Page 22: Expert JavaScript  tricks of the masters

Memoizationsquare()

Page 23: Expert JavaScript  tricks of the masters

Memoizationvar square = function (num) {

return num * num;

};

Page 24: Expert JavaScript  tricks of the masters

Memoization

Problem:

What if the operation is more complex and is called multiple times?

Page 25: Expert JavaScript  tricks of the masters

Memoization

Trick:

Cache the result.

Page 26: Expert JavaScript  tricks of the masters

Memoizationvar square = (function () {

var memo = [];

return function (num) {

var sqr = memo[num];

if (typeof sqr === 'undefined') {

console.log('Calculating...');

memo[num] = sqr = num * num;

}

return sqr;

}

}());

Page 27: Expert JavaScript  tricks of the masters

Memoizationvar fetchData = (function () {

var data = null, timestamp = new Date().getTime();

return function (url, callback) {

if (timestamp - new Date().getTime() > 60000) {

$.ajax(url, {success: function (d) {

timestamp = new Date().getTime();

data = d;

callback(data);

});

} else {

callback(data);

}

}

}());

Page 28: Expert JavaScript  tricks of the masters

Function Overloading

Page 29: Expert JavaScript  tricks of the masters

Function overloading

calculateAverage()

Page 30: Expert JavaScript  tricks of the masters

Function overloading

> calculateAverage([10, 20, 30, 40, 50])

30

Page 31: Expert JavaScript  tricks of the masters

Function overloading

function calculateAverage(values) {

var total = 0;

values.forEach(function (val) {

total += val;

});

return total / values.length;

}

Page 32: Expert JavaScript  tricks of the masters

Function overloading

> calculateAverage(10, 20, 30, 40, 50)

30

Page 33: Expert JavaScript  tricks of the masters

Function overloading

How many arguments are being passed?

Page 34: Expert JavaScript  tricks of the masters

Function overloading

Use the arguments object.

function returnArgs() { return arguments;}

> returnArgs('hello', 'world');["hello", "world"]

Page 35: Expert JavaScript  tricks of the masters

Function overloading

arguments is not an Array.

Does not have any Array properties except length. Not very useful.

Page 36: Expert JavaScript  tricks of the masters

Function overloading

arguments can be converted into an array:

var args = Array.prototype.slice.call(arguments);

Page 37: Expert JavaScript  tricks of the masters

Function overloadingfunction calculateAverage(values) {

var total = 0;

if (!Array.isArray(values)) {

values = Array.prototype.slice.call(arguments);

}

values.forEach(function (val) {

total += val;

});

return total / values.length;

}

Page 38: Expert JavaScript  tricks of the masters

Function overloading

> calculateAverage('10, 20, 30, 40, 50')

30

Page 39: Expert JavaScript  tricks of the masters

Function overloadingfunction calculateAverage(values) {

var total = 0;

if (typeof values === 'string') {

values = values.split(',');

} else if (typeof values === 'number') {

values = Array.prototype.slice.call(arguments);

}

values.forEach(function (val) {

total += parseInt(val, 10);

});

return total / values.length;

}

Page 40: Expert JavaScript  tricks of the masters

Async Code Execution

Page 41: Expert JavaScript  tricks of the masters

Async Code Execution

What does this code do?

// Load appointments for April$.ajax('/calendar/2014/04/');

// Show the calendarshowCalendar();

Shows an empty calendar.

Page 42: Expert JavaScript  tricks of the masters

Async Code Execution

Ajax requests are asynchronous.

The JavaScript engine doesn’t wait.

// Load appointments for April$.ajax('/calendar/2014/04/');

// Show the calendarshowCalendar();

Page 43: Expert JavaScript  tricks of the masters

Async Code Execution

Event-driven programming where callback functions are assigned as event handlers.

When X happens, do Y. Where X is the event and Y is the code to execute.

Page 44: Expert JavaScript  tricks of the masters

Async Code Execution

Assigning an Ajax event handler:

// Load appointments for April$.ajax('/calendar/2014/04/', {

complete: showCalendar});

Page 45: Expert JavaScript  tricks of the masters

Async Code Execution

Event handler assignment:

document.onclick = function (e) {

e = e || event;

console.log('Mouse coords: ', e.pageX, ' / ', e.pageY);

}

Page 46: Expert JavaScript  tricks of the masters

Async Code Execution

Event handler assignment:document.addEventListener('click', function (e) {

e = e || event;

console.log('Mouse coords: ', e.pageX, ' / ', e.pageY);

});

document.addEventListener('click', function (e) {

e = e || event;

var target = e.target || e.srcElement;

console.log('Click target: ', target);

});

Page 47: Expert JavaScript  tricks of the masters

Async Code Execution

Event handler assignment:

var xhr = new XMLHttpRequest();

xhr.onload = function () {

console.log(this.responseText);

}

xhr.open('get', ’/weather_data');

xhr.send();

Page 48: Expert JavaScript  tricks of the masters

Async Code Execution

Event handler context:

document.onclick = function (e) {

// `this` refers to document object

e = e || event;

console.log('Mouse coords: ', e.pageX, ' / ', e.pageY);

}

Page 49: Expert JavaScript  tricks of the masters

Async Code Execution

Event handler context:

xhr.onload = function () {

// `this` refers to xhr object

console.log(this.responseText);

}

Page 50: Expert JavaScript  tricks of the masters

Async Code Execution

this refers to XMLHttpRequest object:

Page 51: Expert JavaScript  tricks of the masters

Execution Context

Page 52: Expert JavaScript  tricks of the masters

Execution Context

Need to execute callback in different contexts where this doesn’t refer to the same thing.

Page 53: Expert JavaScript  tricks of the masters

Execution Context

Use apply, call or bind to change execution context.

Page 54: Expert JavaScript  tricks of the masters

Execution Context

Usage:

doSomething.apply(context, args);

doSomething.call(context, arg1, arg2, ... argN);

var doIt = doSomething.bind(context, arg1, arg2, … argN);

Page 55: Expert JavaScript  tricks of the masters

Execution Context

Let’s bootstrap our earlier Ajax example to demonstrate.

Page 56: Expert JavaScript  tricks of the masters

Execution Context

Ajax event handler assignment from earlier:

var xhr = new XMLHttpRequest();

xhr.onload = function () {

console.log(this.responseText);

}

xhr.open('get', '/weather_data');

xhr.send();

Page 57: Expert JavaScript  tricks of the masters

Execution Context

Bootstrap data rendered into the page:<script>

var bootstrapData = {

"responseText": {

  "weather": {

    "high": "35 ºC",

    "low": "24 ºC",

    "precipitation": "0%",

    "humidity": "78%",

    "wind": "13 km/h"

}

}

};

</script>

Page 58: Expert JavaScript  tricks of the masters

Execution Context

Start with refactoring our callback:

function parseData () {

console.log(this.responseText);

}

var xhr = new XMLHttpRequest();

xhr.onload = parseData;

xhr.open('get', '/weather_data');

xhr.send();

Page 59: Expert JavaScript  tricks of the masters

Execution Context

Set Ajax code to poll every 15 seconds:

function parseData () {console.log(this.responseText);}

var xhr = new XMLHttpRequest();

xhr.onload = parseData;

setInterval(function () {

xhr.open('get', '/weather_data');

xhr.send();

}, 15000);

Page 60: Expert JavaScript  tricks of the masters

Execution Context

bootstrapData is a global variable:<script>

var bootstrapData = {

"responseText": {

  "weather": {

    "high": "35 ºC",

    "low": "24 ºC",

    "precipitation": "0%",

    "humidity": "78%",

    "wind": "13 km/h"

}

}

};

</script>

Page 61: Expert JavaScript  tricks of the masters

Execution Context

Parse bootstrap data immediately on page load:

function parseData () {

console.log(this.responseText);

}

parseData.call(bootstrapData);

Page 62: Expert JavaScript  tricks of the masters

Prototypal Inheritance

Page 63: Expert JavaScript  tricks of the masters

Prototypal Inheritance

“All objects in JavaScript are descended from Object”

var myObject = new Object(); ObjectObject

myObjectmyObject

Page 64: Expert JavaScript  tricks of the masters

Prototypal Inheritance

“All objects in JavaScript are descended from Object”

Object.prototype.hello = 'world';

var myObject = new Object();

Object.helloObject.hello

myObject.hello

myObject.hello

Page 65: Expert JavaScript  tricks of the masters

Prototypal Inheritance

In JavaScript, functions can act like objects.

Page 66: Expert JavaScript  tricks of the masters

Prototypal Inheritance

They have a prototype property allowing inheritance.

function Person() {};Person.prototype.name = "Bob";

Page 67: Expert JavaScript  tricks of the masters

Prototypal Inheritance

You can create an instance of one using the new keyword:

var person1 = new Person();console.log(person1.name); // Bob

Page 68: Expert JavaScript  tricks of the masters

Prototypal Inheritance

Live link with its parent:

function Animal() {}

var dog = new Animal();

Animal.prototype.speak = function (msg) {

console.log(msg)

};

Page 69: Expert JavaScript  tricks of the masters

Prototypal Inheritance

Live link with its parent:

function Animal() {}

var dog = new Animal();

Animal.prototype.speak = function (msg) {

console.log(msg)

};

dog.speak('woof');

Page 70: Expert JavaScript  tricks of the masters

requestAnimationFrame, CSS transforms

Optimization

Page 71: Expert JavaScript  tricks of the masters

Optimization

Improving event handlers with delegation

Page 72: Expert JavaScript  tricks of the masters

Optimization

Rather than assigning individual handlers:

var a = document.getElementById('save');

a.onclick = function () {

// save code

};

Page 73: Expert JavaScript  tricks of the masters

Optimization

Assign one for all of the same type:

document.onclick = function (e) {

e = e || event;

var target = e.target || e.srcElement;

if (target.id === 'save') {

// save code

}

};

Page 74: Expert JavaScript  tricks of the masters

Optimization

Improving animation

Page 75: Expert JavaScript  tricks of the masters

Optimization

Improving animation

setInterval(function () {

someElement.style.left = (leftValue + 1) + "px";

}, 0);

Page 76: Expert JavaScript  tricks of the masters

Optimization

Improve animation with requestAnimationFrame

Key differences: •Animation stops when running in hidden tab•Browser optimized repaint/reflow

Page 77: Expert JavaScript  tricks of the masters

Optimization

Animation stops when running in hidden tab

•Uses less GPU/CPU•Uses less memory

Translation = longer battery life

Page 78: Expert JavaScript  tricks of the masters

Optimization

Browser optimized repaint/reflow

Changes to CSS and the DOM cause parts or all of the document to be recalculated.

Page 79: Expert JavaScript  tricks of the masters

Optimization

Source: https://developer.mozilla.org/en/docs/Web/API/window.requestAnimationFrame

requestAnimationFrame compatibility

Page 80: Expert JavaScript  tricks of the masters

Optimization

Source: https://developer.mozilla.org/en/docs/Web/API/window.requestAnimationFrame

requestAnimationFrame compatibility

Page 81: Expert JavaScript  tricks of the masters

Security

Page 82: Expert JavaScript  tricks of the masters

Security

Avoid eval

Page 83: Expert JavaScript  tricks of the masters

Security

Use literals

[] instead of new Array(){} instead of new Object()

Page 84: Expert JavaScript  tricks of the masters

Security

Use literals

Array = function () {

// I am pretending to be an array.

// I am doing something evil with your data.

}

Page 85: Expert JavaScript  tricks of the masters

Security

External scripts make your application insecure.

Page 86: Expert JavaScript  tricks of the masters

Thank you!

Happy to answer your questions throughout the conference and afterwards!

[email protected]

twitter.com/ara_p