5. let - block scope variable declaration
- block scope variable declaration
if(true) {
let x = 1;
}
console.log(x); // ReferenceError: x is not defined
for(let val of [1, 2, 3, 5]) {
/*...*/
}
console.log(val); // ReferenceError: val is not defined
6. let - block scope variable declaration
- does not hoist (TDZ)
if(true) {
console.log(x); // ReferenceError: foo is not defined
let x = 42;
}
7. const
- similar to let
- must be initialized on declaration
const x; // SyntaxError: missing = in const declaration
- fail silently on reassignment (firefox and chrome)
const x = 1;
x = -1; // fails silently
- throws error on redeclaration
const x = 3.14159;
const x = 2.71828; // TypeError: redeclaration of const x
8. arrow functions - improved syntax
let inc = function(a) { return a + 1; };
let sum = function(a, b) { return a + b; };
let arr = [1, 2, 3, 7, 22];
arr.map(function(n) { return n + 2; })
.filter(function(n) { return n > 8; });
let inc = a => a + 1;
let sum = (a, b) => a + b;
let arr = [1, 2, 3, 7, 22];
arr.map(n => n + 2).filter(n => n > 8);
9. arrow functions - lexical “this”
<button id="btn">Click</button>
<script>
function Widget() {
this.clickCounter = 0; // (1)
document.querySelector('#btn').addEventListener('click', function() {
this.clickCounter++; // “this” here is different from “this” on line (1)
console.log(this.clickCounter);
});
};
var mywidget = new Widget();
</script>
10. arrow functions - lexical “this”
<button id="btn">Click</button>
<script>
function Widget() {
this.clickCounter = 0;
var self = this;
document.querySelector('#btn').addEventListener('click', function() {
self.clickCounter++; // use “self” instead of “this”
console.log(this.clickCounter);
});
};
var mywidget = new Widget();
</script>
11. arrow functions - lexical “this”
<button id="btn">Click</button>
<script>
function Widget() {
this.clickCounter = 0; // (1)
document.querySelector('#btn').addEventListener('click', () => {
this.clickCounter++; // “this” here is the same as “this” from line (1)
console.log(this.clickCounter);
});
};
var mywidget = new Widget();
</script>
12. arrow functions - nice for higher order functions
let notEquals = function(a) {
return function(b) {
return a !== b;
}
};
let notEquals = a => b => a === b;
[2, 3, 5, 7, 11].filter(notEquals(5)); // [2, 3, 7, 11]
// notEquals(5) == b => 5 !== b
13. for...of loops
- iterates over values
let arr = [2, 7, 1, 8, 2, 8];
for(let index in arr) {
console.log(index); // 0, 1, 2, 3, 4, 5
}
for(let value of arr) {
console.log(value); // 2, 7, 1, 8, 2, 8
}
14. tail call optimisation
- tail call is when the last thing a function does is to call another function
- it reuses the current stack frame
- it encourages the use of recursive functions and generally programming in a
functional style
15. default function parameters
function fuu(a, b = 1) {
console.log(‘a =’, a, ‘;‘, ‘b =’, b);
}
fuu(); // a = undefined; b = 1
fuu(2); // a = 2; b = 1
fuu(2, 3); // a = 2; b = 3
16. rest parameters
- accumulate the rest of the parameters from a function call
function baar(a, b, ...c) {
console.log(a, b, c);
}
baar(1); // 1 undefined Array[ ]
baar(1, 4); // 1 4 Array[ ]
baar(1, 4, 11); // 1 4 Array[11]
baar(1, 4, 11, 30); // 1 4 Array[11, 30]
17. spread operator
- expands an iterator where multiple values are expected
fn(...[1, 2, 3]); // equivalent to fn(1, 2, 3)
fn(1, 2, …[7, 41]); // equivalent to fn(1, 2, 7, 41)
let a = [1, 2], b = [4, 5, 6];
let c = [3, 4, ...a]; // c = [3, 4, 1, 2]
let d = [...a, ...b]; // d = [1, 2, 4, 5, 6]
18. object literal extensions
- computed properties
let a = ‘b’;
let c = {
[a]: 4,
[‘a’ + a + ‘c’]: 5
};
console.log(c.b); // 4
console.log(c.abc); // 5
19. object literal extensions
- shorthand properties
let x = 1, y = 2;
let obj;
obj = {x, y, z: 3}; // equivalent to “obj = {x: x, y: y, z: 3}”
- shorthand methods
obj = { sum(a, b) { return a + b; } }
obj.sum(6, 11); // 17
20. object literal extensions
- computed shorthand methods
let myMethod = ‘sum’;
let obj = { [myMethod](a, b) { return a + b; } };
obj.sum(6, 11); // 17
21. template strings
let s = `just made you read this`;
let five = 5,
t = `2 + 2 is ${2 + 2} not ${five}`;
// multiline
let criticilor = `Critici voi, cu flori desarte,
Care roade n-ati adus
E usor a scrie versuri
Când nimic nu ai de spus.
(Mihai Eminescu)`;
22. template strings - tag functions
function mytag(strings, ...values) {
console.log(strings[0]); // “roses are not “
console.log(strings[1]); // “, violets are not “
console.log(values[0]); // “blue”
console.log(values[1]); // “red”
return ‘anything you want’;
}
let r = ‘red’, b = ‘blu’;
mytag`roses are not ${b + ‘e’}, violets are not ${r}`; // ”anything you want”
23. destructuring
let [a, b, c] = [-1, -2, -3];
console.log(‘a =’, a, ‘b =’, b, ‘d !=’, c); // a = -1 b = -2 d != -3
let [ , , d] = [4, 5, -6];
console.log(‘d =’, d); // d = -6
let [e, [f, [g]]] = [7, [8, [9]]];
let [first, ...rest] = [‘first’, ‘r’, ‘e’, ‘s’, ‘t’];
console.log(‘first =‘, first, ‘rest =’, rest); // first = ‘first’ rest = [‘r’, ‘e’, ‘s’, ‘t’]
24. let {name: theName, age} = {name: ‘4real Superman Wheaton’, age: 31};
console.log(‘name =’, theName); // name = “4real Superman Wheaton”
console.log(‘age =’, age); // age = 31
let nested = {very: [‘little’, {baby: ‘bird’}] },
{very: [little, {baby}] } = nested;
console.log(‘little =’, little, ‘baby =’, bird); // little = “little” baby = “bird”
let [a = 1, b = 2] = [3]; // a = 3, b = 2
let {w: y = ‘z’} = {v: ‘v’}; // y = ‘z’
destructuring
26. - syntactic sugar over prototypal inheritance
- fundamentally they are functions and just as functions they can have both
forms (as declarations and as expressions)
class
class declaration
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
class expression
let Point = class {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
28. class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y);
this.color = color;
}
}
let cp = new ColorPoint(1, 1, ‘green’));
class - extends and super keywords
29. - generators are functions which can be exited and later re-entered
- their context (variable bindings) will be saved across re-entrances
- returns an iterator
function* idMaker() {
let index = 0;
while(index < 3) yield index++;
}
let gen = idMaker();
console.log(gen.next()); // {value: 0, done: false}
console.log(gen.next()); // {value: 1, done: false}
console.log(gen.next()); // {value: 2, done: false}
console.log(gen.next()); // {value: undefined, done: true}
generators
31. Differences between objects and maps:
● An Object has a prototype, so there are default keys in the map. This could
be bypassed by using map = Object.create(null) since ES5, but was
seldomly done.
● The keys of an Object are Strings and Symbols, where they can be any
value for a Map.
● You can get the size of a Map easily while you have to manually keep track
of size for an Object.
Map - new Map([iterable])
32. - the Set object lets you store unique values of any type, whether primitive
values or object references.
- you can iterate its elements in insertion order
Set - new Set([iterable]);
33. - asynchronous code written in a synchronous manner
- syntactic sugar over generators
function getAPromise() {
return new Promise(resolve => setTimeout(() => resolve(‘hello!’), 3000));
}
async function doStuff() {
let value = await getAPromise();
console.log(‘value of the promise is’, value);
}
doStuff(); // value of the promise is hello!
async/await - ES7 (stage 3)
34. function getData(url) {
return fetch(url);
}
(async function() {
let urls = [‘users/1’, ‘users/2’, ‘users/3’];
for(let data of urls.map(getData)) { // makes requests in parallel
console.log((await data).name); // logs the user names in order
}
}());
async/await - ES7 (stage 3)
35. - asynchronously observing the changes to an object
- it provides a stream of changes in the order in which they occur
let obj = {foo: 0, bar: 1};
Object.observe(obj, function(changes) {
console.log(changes);
});
obj.baz = 2; // [{name: 'baz', object: <obj>, type: 'add'}]
obj.foo = 'hello'; // [{name: 'foo', object: <obj>, type: 'update', oldValue: 0}]
delete obj.baz; // [{name: 'baz', object: <obj>, type: 'delete', oldValue: 2}]
Object.defineProperty(obj, 'foo', {writable: false});
// [{name: 'foo', object: <obj>, type: 'reconfigure'}]
Object.observe - ES7 (stage 2)
36. - proposal for an Observable type
- used to model push-based data sources such as DOM events, timer
intervals, sockets and others
- can be composed with higher-order combinators
- they do not start emitting data until an observer has subscribed
Observables - ES7 (stage 1)
37. function listen(element, eventName) {
return new Observable(observer => {
// Create an event handler which sends data to the observer
let handler = event => observer.next(event);
// Attach the event handler
element.addEventListener(eventName, handler, true);
});
}
Observables - ES7 (stage 1)
38. // Return an observable of special key down commands
function commandKeys(element) {
let keyCommands = { "38": "up", "40": "down" };
return listen(element, "keydown")
.filter(event => event.keyCode in keyCommands)
.map(event => keyCommands[event.keyCode])
}
commandKeys(inputElement).subscribe({
next(val) { console.log("Received key command: " + val) }, // “up” “down” “up” “up” “down” “up”
// error(err) { console.log("Received an error: " + err) },
// complete() { console.log("Stream complete") }
});
Observables - ES7 (stage 1)
39. A decorator is:
- an expression
- that evaluates to a function
- that takes the target, name, and property descriptor as arguments
- and optionally returns a property descriptor to install on the target object
class Person {
@nonenumerable
get kidCount() { return this.children.length; }
}
function nonenumerable(target, name, descriptor) {
descriptor.enumerable = false;
return descriptor;
}
class and property decorators - ES7 (stage 1)
40. - It is also possible to decorate the class itself. In this case, the decorator
takes the target constructor.
@annotation
class MyClass { }
function annotation(target) {
// Add a property on target
target.annotated = true;
}
class and property decorators - ES7 (stage 1)
41. - since decorators are expressions, decorators can take additional arguments
and act like a factory
class C {
@enumerable(false)
method() { }
}
function enumerable(value) {
return function (target, key, descriptor) {
descriptor.enumerable = value;
return descriptor;
}
}
class and property decorators - ES7 (stage 1)