ES6 Ghosts – A little bit of history – let and const



ES6 Ghosts – A little bit of history – let and const

0 5


es6-talk

Talk on ES6 features for Node.js meetup Thessaloniki - Mar 2016

On Github sirodoht / es6-talk

ES6 Ghosts

 

@sirodoht / Node.js Meetup Thessaloniki

A little bit of history

let and const

Block scope variables in C

int main(void) {
	int x = 3;
	{
		int y = 5;
	}
	x = y;  // error: use of undeclared identifier 'y'
}

Function scope variables in JS

function func() {
  {
    var x = 1;
  	if (x === 1) {
			var y = 2;
		}
		console.log(y);  // 2

		var x = 2;  // no error, even though already declared
  }
}
console.log(x);  // ReferenceError: x is not defined

Block scope variables in JS

function func() {
  {
    let x;
    {
      let y = 1;
    }
    let x = "inner";  // error, already declared in block

    console.log(y);  // ReferenceError: y is not defined
  }
}
console.log(x);

Immutable variables

function func() {
  {
    const x = "sneaky";
    x = "foo";  // TypeError: Assignment to constant variable.
  }
}

Only the variable binding is immutable, not the content!

const x = {
  one: 2,
  three: 4
};

x.five = "seven";  // no problem!

x.eight = 9;  // same

x = {
	five: "six"
};  // TypeError: Assignment to constant variable.

Arrow functions

Succinct anonymous functions

// # ES5
[1, 2, 3].map(function(n) {
  return n * 2;
}, this);
// -> [ 2, 4, 6 ]

// # ES6
[1, 2, 3].map(n => n * 2);
// -> [ 2, 4, 6 ]

More than one parameters

[1, 2, 3].map((n, index) => {
  const result = n * index;
  return result;
});
// -> [ 0, 2, 6 ]

Dynamic scope-ish this

function Person() {
  var self = this;
  self.age = 0;

  setInterval(function growUp() {
    self.age++;
  }, 1000);
}

Lexical scope this

function Person(){
  this.age = 0;

  setInterval(() => {
    this.age++; // |this| properly refers to the person object
  }, 1000);
}

class keyword

Pseudo-classical inheritance

function Person(name, age, gender) {
  this.name = name;
  this.age = age;
  this.gender = gender;
}

Person.prototype.incrementAge = function () {
  return this.age += 1;
};

Pseudo-classical inheritance with

class Person {
  constructor(name, age, gender) {
    this.name = name;
    this.age = age;
    this.gender = gender;
  }

	incrementAge() {
  	this.age += 1;
  }
}

Pseudo-classical inheritance (subclass)

function Personal(name, age, gender, occupation, hobby) {
  Person.call(this, name, age, gender);
  this.occupation = occupation;
  this.hobby = hobby;
}

Personal.prototype = Object.create(Person.prototype);
Personal.prototype.constructor = Personal;
Personal.prototype.incrementAge = function () {
  Person.prototype.incrementAge.call(this);
  this.age += 20;
  console.log(this.age);
};

Pseudo-classical inheritance (subclass) with

class Personal extends Person {
  constructor(name, age, gender, occupation, hobby) {
    super(name, age, gender);
    this.occupation = occupation;
    this.hobby = hobby;
  }

  incrementAge() {
    super.incrementAge();
    this.age += 20;
    console.log(this.age);
  }
}

Destructuring Assignment

Using Arrays

var [a, b] = [1, 2];
console.log(a); // 1
console.log(b); // 2

var foo = ["bar", "zoo", "moo"];
var [one, two, three] = foo;
console.log(one); // "bar"
console.log(two); // "zoo"
console.log(three); // "moo"

Using the spread operator

[a, b, ...rest] = [1, 2, 3, 4, 5];
console.log(a); // 1
console.log(b); // 2
console.log(rest); // [3, 4, 5]

Using Objects

var {foo, bar} = {foo: 'lorem', bar: 'ipsum'};
// foo => lorem and bar => ipsum
({a, b} = {a:1, b:2});
console.log(a); // 1
console.log(b); // 2

Using functions and omitting arguments

function f() {
  return [1, 2, 3];
}

var [a, , c] = f();
console.log(a); // 1
console.log(c); // 3

Default parameters

Handling undefined variables

// ES5
function addTwoNumbers(x, y) {
	x = x || 0;
	y = y || 0;
	return x + y;
}

// ES6
function addTwoNumbers(x=0, y=0) {
  return x + y;
}

Named Parameters

jQuery options-like behaviour

// ES5
function initializeCanvas(options) {
	var height = options.height || 600;
	var width = options.width || 400;
	var lineStroke = options.lineStroke || 'black';
}

// ES6
function initializeCanvas({ height=600, width=400}) {
	// Use variables height, width here
}

Rest parameters

Spread operator gives us a real array!

// ES5
function logArguments() {
  for (var i=0; i < arguments.length; i++) {
    console.log(arguments[i]);
  }
}

// ES6
function logArguments(...args) {
  for (let arg of args) {
    console.log(arg);
  }
}

Generators

In the simplest form

function* sillyGenerator() {
  yield 1;
  yield 2;
  yield 3;
  yield 4;
}

var generator = sillyGenerator();
console.log(generator.next()); // { value: 1, done: false }
console.log(generator.next()); // { value: 2, done: false }
console.log(generator.next()); // { value: 3, done: false }
console.log(generator.next()); // { value: 4, done: false }
console.log(generator.next()); // { value: undefined, done: true }

Infinite generator

function* idMaker(){
  var index = 0;
  while (true) {
    yield index++;
  }
}

var gen = idMaker();

console.log(gen.next().value);  // 0
console.log(gen.next().value);  // 1
console.log(gen.next().value);  // 2

Fibonacci !

function* fibonacci(){
  var fn1 = 0;
  var fn2 = 1;
  while (true){
    var current = fn1;
    fn1 = fn2;
    fn2 = current + fn1;
    var reset = yield current;
    if (reset){
      fn1 = 0;
      fn2 = 1;
    }
  }
}

var sequence = fibonacci();
console.log(sequence.next().value);  // 0
console.log(sequence.next().value);  // 1
console.log(sequence.next().value);  // 1
console.log(sequence.next().value);  // 2
console.log(sequence.next().value);  // 3
console.log(sequence.next().value);  // 5
console.log(sequence.next().value);  // 8
console.log(sequence.next(true).value);  // 0
console.log(sequence.next().value);  // 1
console.log(sequence.next().value);  // 1
console.log(sequence.next().value);  // 2

Fibonacci with destructuring

function* fibonacci() {
  let [prev, curr] = [0, 1];
  while (true) {
    [prev, curr] = [curr, prev + curr];
    let reset = yield curr;
    if (reset) {
      [prev, curr] = [0, 1];
    }
  }
}

Fibonacci with destructuring - usage with for...of

for (let n of fibonacci()) {
  console.log(n);
  if (n >= 1000) {
    break;
  }
}

Spread operator can also run a generator

function* fibonacci(n) {
  const infinite = !n && n !== 0;
  let current = 0;
  let next = 1;
  while (infinite || n--) {
    yield current;
    [current, next] = [next, current + next];
  }
}
let [...first10] = fibonacci(10);
console.log(first10);
// [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

Koa middleware

app.use(function *(next) {
  var start = new Date;
  yield next;
  var ms = new Date - start;
  this.set('X-Response-Time', ms + 'ms');
});

Talked about

  • let and const
  • Arrow functions
  • class keyword
  • Destructuring Assignment and Spread Operator
  • Default/Name/Rest Parameters
  • Generators

There is more!

  • Promises
  • Modules
  • String templates
  • Sets (and WeakSets)
  • Maps (and WeakMaps)
  • Symbols (Iterators)
  • Reflection

Questions

Thank you!

/sirodoht/es6-talk
ES6 Ghosts   @sirodoht / Node.js Meetup Thessaloniki