Tuesday, October 17, 2017

JavaScript ES6 ES2015 New Feature Overview

JavaScript adds more useful language features in ES6 (ES2015).

New features can be used right now while being backwards compatible with older browsers by using Babel js which transpiles ES6 to ES5. Babel js can be used in a build step for a js project.
https://babeljs.io/

ES6 be used on the backend (nodeJs) and front end (React, etc.).

Destructuring

Take an object or an array and rip it apart into variables.

// object
var o = {
    p1: 1,
    p2: 2
}
var {p1, p2} = o
console.log (p1, p2)

1 2

// array
var a = [1, 2]
var [v1, v2] = a
console.log (v1, v2)

1 2

// function arguments
var o = {
    arg1: 1,
    arg2: 2
}

var fn = ({arg2, arg3, arg1}) => {
    console.log(arg1, arg2, arg3)
}

fn(o)

1 2 undefined

Spread Operator

function fn(a1, a2, a3){
    console.log(a2)
}

var arr = [1, 2, 3]
fn(...arr)

2

var arr = [1, 2, 3, 4, 5]
var [first, ...theRest] = arr
console.log(first)
console.log(theRest)

1
(4) [2, 3, 4, 5]]

var ar1 = [4, 5]
var ar2 = [1, 2, 3]

var ar = [...ar2, ...ar1, 6]
console.log(ar)

(6) [1, 2, 3, 4, 5, 6]

Template Strings

// use back tick and ${varName}
var name = "Slim Shady"
var formattedStr = `My name is
${name}`

console.log(formattedStr)

My name is
Slim Shady

Block Scoping

// var scoping is at function level
// No matter where a variable is defined in a function,
// the variable is hoisted to the top of the function
// let
// Limits scope of a variable to a block (e.g. if and loop stmt blocks)
// Use let EVERYWHERE instead of var

let v = 1

if (true){
    let v = 2
    console.log(v)
}

console.log(v)

2
1

Constants

// const to define a variable that can be assigned to only once
// However, an object assigned to a const CAN be mutated
// user const everywhere if you prefer immutable objects in JavaScript

const c = 1
c = 2
console.log(c)

Uncaught TypeError: Assignment to constant variable.

Arrow Functions

var fn =(a, b) => {
    return a + b
}
console.log(fn(1, 2))

// implict return
var fn = (a, b) => a + b
console.log(fn(2, 3))

3
5

const total = [0, 1, 2, 3].reduce((sum, value) => sum + value, 1)
console.log(total)

7

// arrow functions automatically set lexical context
// may not be desired when writing callbacks for some libraries,
// such as jQuery where this is bound to jQuery library
var o = {
data: 1,
print : function(){
console.log(this.data)
}
}
 o.print()

1

// must bind to this in order to access the data
var o = {
data: 1,
print : function(){
setTimeout(function() {
console.log(this.data)
}.bind(this), 100)
}
}
o.print()

1

// Alternate: use arrow function, no need to bind this
var o = {
data: 1,
print : function(){
// automatically binds the this context
setTimeout(() => {
console.log(this.data)
}, 100)
}
}
o.print()

1

var numbers = [1,2,3,4,5]
var strings = numbers.map(n => n.toString())
console.log(strings)

(5) ["1", "2", "3", "4", "5"]

// How to use 'this' in a timer function (without arrow functions),
//  whose context is Global context, not the function context
//  this.val is scoped to the function
//  define'that' variable in the function closure to keep a reference to 'this'
//  to be accessed by setTimeout function that runs in global scope
function fn() {
    var that = this
    this.val = 0

    setTimeout(function inc(){
        // can't use this.val because this function is in global scope
        that.val++
    }, 0)

    this.print = function() {
        console.log(that.val)
    }
}

var f = new fn()

setTimeout(() => f.print(), 100)

1

// arrow functions are lexically scoped to the block they are contained
//  now we no longer have to preserve 'this' in 'that' variable
function fn() {
    this.val = 0

    setTimeout(() => {
        this.val++
    }, 0)

    this.print = function() {
        console.log(this.val)
    }
}

var f = new fn()

setTimeout(() => f.print(), 100)

1

Classes

class Base{
    constructor(){
        this.data = 1 
    }
 
    fn(){
        console.log('Base ' + this.data)
    }
}

class Derived extends Base{
constructor(){
        super()
    }
    fn(){
        console.log('Derived ' + this.data)
    }
}

var base = new Base()
base.fn()

var derived = new Derived()
derived.fn()

Base 1
Derived 1

Module System

Replaces 'require' library

Export (module1.js):
module.exports.pi = () => 3.142
module.exports.multidentity = () => 1

// entire module export is replaced with this function
export default function(){
}
// export entire module
export default {
}

To export function:
export function fn(){
}

To export variable:
export const pi = 22/7

To import:
import module1 from "module1"

To import (with destructuring, selectively pull what you need):
import {pi, multidentity} from "module1"

To import with an alias:
import {pi, multidentity as one} from "module1"
console.log(one)

Async (Generator function) Function

async function() {
var data = await $.get(url)
console.log(data)
}