KnowledgeShop

Learn & Share

JavaScript Ecosystem

JS Ecosystem Overview

  • “JavaScript” is not really a single language. Each browser vendor implements their own JavaScript engine, and due to variations between browsers and versions, JavaScript suffers from some serious fragmentation. (CanIUse.com documents some of these inconsistencies).
  • ES6, also known as ES2015 / Harmony / ECMAScript 6 / ECMAScript 2015, is the most-recent version of the JavaScript specification. (good primer on ES6).
  • Transpilers
    • Tools: Babel
    • process of transforming the standardized JavaScript into a version that’s compatible with older platforms is called_ transpiling_. e.g., ES6 to ES5
    • It’s not much different from compiling. By using a transpiler, you don’t need to worry as much about the headaches of whether or not a given browser will support the JavaScript feature you’re using.
    • Transpiler tools don’t just convert ES6 JavaScript to ES5. There are also tools to do the same thing for JavaScript-variants (such as ClojureScript, TypeScript, and CoffeeScript) to regular JavaScript.
      • ClojureScript is a version of Clojure that compiles down to JavaScript.
      • TypeScript is essentially JavaScript, but with a type system.
      • CoffeeScript is very similar to JavaScript, but with shinier syntax; much of the syntactic sugar promoted by CoffeeScript has been adopted by ES6 now.
  • Build Tools
    • Tools: grunt, gulp, bower, browserify, webpack
    • Basically compiling the code into a production-ready format.
    • Requiring each JavaScript dependency as part of a page, script tag by script tag, is slow. Therefore, most sites use so-called JavaScript bundles. The bundling process takes all of the dependencies and “bundles” them together into a single file for inclusion on your page.
  • Test Tools
    • Tools: Mocha, Jasmine, Chai, Tape, Karma, PhantomJS
    • Karma is a test runner that can run both Jasmine and Mocha-style tests.
    • PhantomJS is a headless browser - it runs without GUI.

Node.js

  • Node.js is a tool for writing server-side JavaScript.
  • npm Node package manager. JavaScript modules are usually packaged and shared via npm.
  • nvm Node version manager. Facilitates managing different version of Node.js.

Runtime Environment

  • Node.js is not a language; not a framework; not a tool. It is a runtime environment for running JS-based applications like JRE for Java.
  • JavaScript Virtual Machine (JsVM)
    • Node.js has a virtual machine called JavaScript Virtual Machine (JsVM) which generates machine code for JS-based applications to enable it on different platforms.
    • We have separate Node.js requirements for different platforms like Windows, Macintosh, and Linux and hence the JsVM.
    • V8 is an open source JavaScript engine from Google. (Nashorn is the Java-based JS engine in JVM). Like the JVM, the JsVM (V8 engine) also has main components like JIT and GC for performing tasks, runtime compilation, and memory management respectively.
  • Node.js also has a set of libraries which may otherwise be known as Node API or Node Modules to help run JS applications at runtime, similar to Java Libraries within the JRE.

  • How the JavaScript program is compiled and executed.
    • The source code is written in JavaScript (.js). There is no intermediate code generated before giving it to JsVM, the V8 engine.
    • The JsVM takes this source code directly and compiles it to machine code specific to the given target platform for execution.

Web Application Architecture

  • The client requests are handled by a single thread, but asynchronously. With Java, each client request is handled by a separate thread synchronously.
  • There are many frameworks/libraries available for Node.js-based web application development. E.g., Express.js, Angular.js, Mongoose.js, etc.
    • Client layer: Angular.js, a client-side MVC framework.
    • Presentation + Service layer: can be developed by using Express.js. This also comes with a standalone server for running Node.js applications.
    • Data layer: uses an Object Data Modelling module (e.g. Mongoose.js) for communicating with NoSQL databases like MongoDB.
    • This particular stack is called MEAN stack , which consists of MongoDB, Express.js, Angular.js, and Node.js (the runtime environment)

ES6 Basics

  • Another name for ES6 is ES2015.

  • Good tutorial https://babeljs.io/docs/en/learn
  • MDN documentation https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export

Arrow Functions

1
2
3
4
5
let createGreeting = function(message, name){
  return message + name;
}

let arrowGreeting = (message,name) => message + name;

let keyword

using var
1
2
3
4
5
6
var message = "hi";
{
  var message = "bye";
}

console.log(message); // prints bye
using let
1
2
3
4
5
6
let message = "hi";
{
  let message = "bye";
}

console.log(message); // prints hi

Default values in function parameters

example of default value in parameter
1
2
3
4
5
function greet(greeting, name = "John"){
  console.log(greeting + ", " + name);
}

greet("Hello");// prints Hello John
example of a function as a default value
1
2
3
function receive(complete = () => console.log("complete")){
  complete();
}

or even better

1
let receive = (complete = () => console.log("complete")) => complete();

Shorthand properties

1
2
3
4
5
6
let firstName = "John";
let lastName = "Lindquist";

let person = {firstName, lastName}

console.log(person); //prints { firstName: 'John', lastName: 'Lindquist' }
nested example
1
2
3
4
5
6
7
8
9
let firstName = "John";
let lastName = "Lindquist";

let person = {firstName, lastName}

let mascot = "Moose";
let team = {person, mascot};

console.log(team); //prints {  person: { firstName: 'John', lastName: 'Lindquist' },   mascot: 'Moose' }
Object enhancements
1
2
3
4
5
6
7
let color = "red";
let speed = 10;

let car = {color, speed};

console.log(car.color); // "red"
console.log(car.speed); // 10
1
2
3
4
5
6
7
8
9
10
11
let car = {
  color,
  speed,
  go(){
    console.log("vroom");
  }
};

console.log(car.color); // "red"
console.log(car.speed); // 10
console.log(car.go()); // "vroom"

Spread operator

The spread operator allows you to “explode” an array into its individual elements.

1
2
console.log([ 1, 2, 3]); // [1, 2, 3]
console.log(...[ 1, 2, 3]) // 1 2 3
add without spread operator
1
2
3
4
5
6
let first = [ 1, 2, 3];
let second = [ 1, 2, 3];

first.push(second);

console.log(first); // [ 1, 2, 3, [ 4, 5, 6] ]
add with spread operator
1
2
3
first.push(...second);

console.log(first); // [1, 2, 3, 4, 5, 6]
spread as input parameters
1
2
3
4
5
6
function addThreeThings( a, b, c){
  let result = a + b + c;
  console.log(result); // 6
}

addThreeThings(...first);

Template Literals

1
2
3
4
let name = "Hans"
let message = `Hello ${name}. It's ${new Date().getHours()} I'm sleepy`;

console.log(message); // "Hello Hans. It's 15 I'm sleepy"
Passing template literal to a function
1
2
3
4
5
6
7
function foo(strings, ...values){
  console.log(strings); // [ 'Hello ', ". It's ", " I'm sleepy" ]
  console.log(values);  // [ 'Hans', 20 ]
}

let name = "Hans"
let message = foo`Hello ${name}. It's ${new Date().getHours()} I'm sleepy`;

Destructuring Assignments

old style
1
2
3
4
5
let obj = {
  name: "john",
  color: "blue"
}
console.log(obj.color); // blue
1
2
3
4
5
6
let obj = {
  name: "john",
  color: "blue"
}
let {color} = obj
console.log(color); // blue
Multiple properties
1
2
3
4
5
6
7
8
9
let {color, position} = {
  color: "blue",
  name: "John",
  state: "New York",
  position: "Forward"
}

console.log(color);
console.log(position);
Give a new variable name
1
2
3
4
5
6
7
8
9
10
11
12
13
function generateObj() {
  return {
    color: "blue",
    name: "John",
    state: "New York",
    position: "Forward"
  }
}

let {name:firstname, state:location} = generateObj();

console.log(firstname); // John
console.log(location); // New York
Destructuring array items
1
2
3
4
let [first,,,,fifth] = ["red", "yellow", "green", "blue", "orange"]

console.log(first); // red
console.log(fifth); // orange
Print first names only
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let people = [
  {
    "firstName": "Skyler",
    "lastName": "Carroll",
    "phone": "1-429-754-5027",
    "email": "Cras.vehicula.alique@diamProin.ca",
    "address": "P.O. Box 171, 1135 Feugiat St."
  },
  {
    "firstName": "Kylynn",
    "lastName": "Madden",
    "phone": "1-637-627-2810",
    "email": "mollis.Duis@ante.co.uk",
    "address": "993-6353 Aliquet, Street"
  },
]

people.forEach(({firstName})= > console.log(firstName))
// Skyler
// Kylynn
Destructuring in function parameters
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
let people = [
  {
    "firstName": "Skyler",
    "lastName": "Carroll",
    "phone": "1-429-754-5027",
    "email": "Cras.vehicula.alique@diamProin.ca",
    "address": "P.O. Box 171, 1135 Feugiat St."
  },
  {
    "firstName": "Kylynn",
    "lastName": "Madden",
    "phone": "1-637-627-2810",
    "email": "mollis.Duis@ante.co.uk",
    "address": "993-6353 Aliquet, Street"
  },
]

let [,secondperson] = people;

function logEmail({email}){
  console.log(email);
}

logEmail(secondperson) // mollis.Duis@ante.co.uk

Modules

A function is declared and exported from a file named math/addition.js.

math/addition.js
1
2
3
4
5
function sumTwo(a,b){
  return a + b;
}

export { sumTwo }

To use the above function in a different file,

import the module
1
2
3
4
5
6
import { sumTwo } from `math/addition`;

console.log(
  "2 + 3 + 4 = ",
  sumThree(2, 3, 4)
); // 2 + 3 + 4 = 9

We can also directly export on the function definition.

math/addition.js - Using export directly on the function definition
1
2
3
4
5
6
7
export function sumTwo(a,b){
  return a + b;
}

export function sumTwo(a,b,c){
  return a + b + c;
}
import a function using an alias
1
2
3
4
import {
  sumTwo as addTwoNumbers,
  sumThree
} from 'math/addition';

We can also import all the functions from the module using *.

Import all
1
2
3
4
5
6
7
8
9
10
11
import * as addition from 'math/addition';

console.log(
  "1 + 3",
  addition.sumTwo(1, 3) // 4
);

console.log(
  "1 + 3 + 4",
  addition.sumTwo(1, 3, 4) // 8
);

3rd party modules can be imported in the same fashion. Say, npm install --save lodash

main.js Import lodash
1
import * as _ from 'lodash';

Promises

  • Promises in ES6 are very similar to those of Angular’s $q service.
  • The callback inside of a promise takes two arguments, resolve and reject.
  • Promises can either be resolved or rejected. When you resolve a promise, the .then() will fire, and when you reject a promise, the .catch() will fire instead. Usually, inside of your promise, you have some sort of logic that decides whether you’re going to reject or resolve the promise.
  • The .then() method callback also takes an argument. This one we’ll call data. The value for data is the argument that is passed into the resolve method.
  • Alternatively, in the .catch() method, we also have a callback function as the argument, but here, what will be passed back is the information that’s supplied into the reject method of our promise.
Promise example
1
2
3
4
5
6
7
8
9
10
11
let d = new Promise((resolve, reject) => {
  if (true) {
    resolve('hello world');
  } else {
    reject('no bueno');
  }
});

d.then((data) => console.log('success : ', data));

d.catch((error) => console.error('error : ', error));
  • Promises are useful for a lot of things. Most importantly, they allow you to perform asynchronous operations in a synchronous-like manner
  • For example, let’s add a 2 seconds timeout in the above code
Promise with delay
1
2
3
4
5
6
7
8
9
let d = new Promise((resolve, reject) => {
  setTimeout(() => {
    if (true) {
      resolve('hello world');
    } else {
      reject('no bueno');
    }
  }, 2000);
});

There is a variation of .then() method which takes error function as a 2nd parameter. But from readability perspective, it is better to keep them separate.

1
2
3
d.then ((data) => console.log('success : ', data), (error) => {
  console.error('new error msg: ', error);
});

Several .then methods can be chained together and have them called in succession. In this case, once the resolve is called, both .thens will fire one after another.

chained then methods
1
2
3
d.then((data) => console.log('success : ', data))
  .then((data) => console.log('success 2 : ', data)) //prints "success 2 : undefined"
  .catch((error) => console.error('error : ', error));

As you notice, the 2nd then input parameter data is undefined. This is because the data that’s available in the callback of the second then is not what is originally passed into the resolve but rather what is returned from the 1st .then method.

chained then version 2
1
2
3
4
5
6
d.then((data) => {
    console.log('success : ', data);
    return 'foo bar';
  })
  .then((data) => console.log('success 2 : ', data)) //prints "success 2 : foo bar"
  .catch((error) => console.error('error : ', error));

References