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 3

Function 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 8

Async 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!

http://exploringjs.com/

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...

Thanks!

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