Javascript
The Good, the Bad and the Ugly
Jaroslav Kubicek
@kubajzHK

Once upon a time in the JavaScript world...
JavaScript aka Mocha aka LiveScript aka ECMAScript..
- born in 1995 in Netscape to battle IE (within 10 days)
- named by "marketing"
- many browsers === many interpreters
- DOM interface defined by different authority (W3C)
- new version of language is forced to all users
(even if they don't want to)

JavaScript - the good parts




ECMAScript
ES1 - 1997
ES2 - 1998
ES3 - 1999
ES4 s*it happens..
ES5 - 2009
ES6 - 2015 (renamed to ES2015)

Function declaration
- it's all almost the same, but still different...
function returnSomething(param) {
}
var anonymous = function() {
return 'I am anonymous';
};
var fatArrow = () => 'I am lambda & ES6 only!';
new Function('a', 'b', 'return a + b'); // don't be the bad guy!
console.log(typeof fnA); // function
console.log(typeof fnB); // undefined - HA!
function fnA () {}
var fnB = function() {};Scope
&
Context

Scope
- how variables are resolved
Context
- this object - reference to the object that "owns" currently executing code
Variable scope
- defined at the creation phrase of the execution
- each function defines new scope
- code in inner (child) scope can access variables defined in outer (parent) scope
- variables defined in current scope take precedence over variables in parent scope
var defineA = function() {
var a = 'AAA';
var hello = 'Hello!';
var defineB = function() {
var b = 'BBB';
var defineC = function() {
var c = 'CCC';
var hello = 'Hi!';
console.log(a, b, c);
console.log(hello);
};
defineC();
};
defineB();
};
defineA();
/*
Outputs:
AAA BBB CCC
Hi!
*/Closure
var functions = [];
for (var i = 0; i < 3; i++) {
functions.push(function () {
console.log(i)
});
}
functions.forEach(function (fn) {
fn(); // outputs 3 three times
});
var functionsAgain = [];
for (var j = 0; j < 3; j++) {
functionsAgain.push(function (number) {
return function () {
console.log(number);
}
}(j));
}
functionsAgain.forEach(function (fn) {
fn(); // outputs 0, 1 and 2
});'use strict';
var es6only = [];
for (let k = 0; k < 3; k++) {
es6only.push(function () {
console.log(k);
});
}
es6only.forEach(function (fn) {
fn(); // outputs 0, 1 and 2
});
Context
- determined by how was a function called (at the execution time)
...but I can change it!
var obj = {
length: 5,
printLength: function () {
console.log(this.length);
}
};
obj.printLength(); // outputs 5
var printLength = obj.printLength;
printLength(); // outputs undefined
var fruits = ['banana', 'apple', 'orange'];
var newPrintFunction = obj.printLength.bind(fruits);
newPrintFunction(); // outputs 3Function currying
class App extends React.Component {
_onClick(people, event) {
alert(`Hello ${people}`);
event.stopPropagation();
}
render() {
return (<button onClick={this._onClick.bind(this, 'ROCdevs')}>Click me!</button>)
}
}
var add = function(a, b) {
console.log(a + b);
};
var addFive = add.bind(null, 5);
addFive(3); // outputs 8Async event loop

and how to deal with it...
Async event loop
How to block user's browser - in few steps...
class Form extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
}
_onChange(event) {
callHarakiriAction();
this.setState({value: event.target.value});
}
render() {
// NOTE: textarea value="" is React.js magic
return (
<form action="" method="post">
<textarea
name="message"
value={this.state.value}
onChange={this._onChange.bind(this)}
/>
</form>
);
}
}How to deal with async - callbacks

And what is bad with them?
Callbacks
var getPost = function(postId, callback) {
cache.get(postId, function(err, post) {
if (err) {
logError(err);
}
if (post) {
return callback(null, post);
}
backendService.get(postId, function(err, post) {
if (err) {
return callback(err);
}
if (!post) {
return callback(new Error('Post not found'));
}
cache.save(postId, post, function(err) {
if (err) {
logError(err);
}
callback(null, post);
});
})
})
};Why is it bad?
- possibility of pyramid of doom is not the worst thing ...
- INVERSION OF CONTROL - you give over control of the execution to something else and you have to trust that it behaves as it was intended
Callbacks - trust issues
You trust that:
- callback will be called
- ... and it will be called exactly once
- ... and first argument will be error
- ... and if some error appears, it will not be swallowed by medusa
This happens more often than you think!
https://github.com/getify/You-Dont-Know-JS/blob/master/async%20%26%20performance/ch2.md#trust-issues
Promises
It's better, because...
- it is standardized
- callback function will be called exactly once no matter what
- it will succeed (resolve) or fail (reject)
- unexpected errors are handled
...because PROMISES ARE SAFE!

Promises
getProfile(userId)
.then(function (user) {
return getFollowers(user.followersIds);
})
.then(function (followers) {
return Promise.all(followers.map(function (follower) {
return sendDirtyMessage(userId, follower);
}));
})
.then(function () {
console.log(`${userId} has no followers!`);
})
.catch(function (error) {
// some error happens, handle it!
});Promises + generators (and beyond)

Promises + generators
var blackMagic = function() {
// 10-20 lines of pure magic
};
blackMagic(function* {
var user = yield getPost(postId);
var followers = yield getFollowers(user.followersIds);
try { // event try/catch is possible now!
yield sendDirtyMessageToAll(followers);
} catch(e) {
throw MyCustomError(':-(');
}
return user;
})
.then(() => console.log('yay!'))
.catch((error) => console.log(error));Async/await
async function {
var user = await getPost(postId);
var followers = await getFollowers(user.followersIds);
try {
await sendDirtyMessageToAll(followers);
} catch(e) {
throw MyCustomError(':-(');
}
return user;
}
Learn ES2015 today!
Generators:
function* () {
var index = 0;
while(true) yield index++;
}Native Promises:
Promise.all()
Promise.reject()
Promise.resolve()Arrow functions:
var goodFunction = () => {
console.log(this); // this object I can live with
}Template literals:
var message = `My name is ${user}`;... and many many more!
Some tips for the end...
- console.log is neither for debugging nor for logging
use winston: https://github.com/winstonjs/winston - Use underscore/lodash for javascript weird stuff
(typeof null === 'object') https://lodash.com/ - Use async library when working with callbacks: https://github.com/caolan/async
- use high order functions (map, filter, reduce)
http://eloquentjavascript.net/05_higher_order.html - JavaScript is minimalistic - deal with it (and don't try to change it)
Thanks!
@kubajzHK
gib me starzs plz!

JavaScript - the good, the bad and the ugly
By Jaroslav Kubíček
JavaScript - the good, the bad and the ugly
- 943