@ Rakuten Taiwan weekly meetup
function order(x, y) {
if (x > y) {
let tmp = x;
x = y;
y = tmp;
}
console.log(tmp === x); // ReferenceError: tmp is not defined
return [x, y];
}
Block Scope
Immutable (?)
const foo;
// SyntaxError: missing = in const declaration
const bar = 123;
bar = 456;
// TypeError: `bar` is read-only
In ECMAScript 6, accessing a let or const variable before its declaration (within its scope) causes a ReferenceError. The time span when that happens, between the creation of a variable’s binding and its declaration, is called the temporal dead zone.
- Dr. Axel Rauschmayer
// Example from exploringjs
typeof tmp === 'boolean'; // ReferenceError
let tmp = true;
if (true) { // enter new scope, TDZ starts
// Uninitialized binding for `tmp` is created
console.log(tmp); // ReferenceError
let tmp; // TDZ ends, `tmp` is initialized with `undefined`
console.log(tmp); // undefined
tmp = 123;
console.log(tmp); // 123
}
console.log(tmp); // true
There are two kinds of literals:
Template literals: multi-line string literals that support interpolation
Tagged template literals: function calls
// String interpolation
const name = 'Haku';
console.log(`Hello, ${name}
Welcome to Rakuten!`);
console.log(`Use backslash(\\) as same as
normal string to escape itself.`)
// Output:
// Hello, Haku
// Welcome to Rakuten!
// Use backslash(\) as same as
// normal string to escape itself.
String.raw`You can use
\nthis multiple lines
\rexample string
\tto check
how String.raw works
\n`;
sayHello`Hello, ${name}
Welcome to ${companyName}!`
// equal to below syntax
sayHello(
['Hello, ', '\nWelcome to ', '!'],
name,
companyName
)
Putting a template string after function expression without parentheses will trigger a function call.
Check following example:
The tag function will receive Template strings as first parameter and Substitutions (such as name in the previous example) as other parameters.
Besides, tag function will receive two versions of template strings:
1. raw: backslashes are not interpreted
2. cooked: backslashes are special
Check next page for full sample code.
function sayHello(literals, ...subs) {
return literals.reduce((result, lit, idx) => (
(idx < subs.length) ?
`${result}${lit}${subs[idx].toUpperCase()}` :
`${result}${lit}`
), '');
}
const name = 'Haku';
const companyName = 'Rakuten';
sayHello`Hello, ${name}
Welcome to ${companyName}!`
// Output:
// Hello, HAKU
// Welcome to RAKUTEN!
Initialize parameter values with default value if no value or undefined is passed, default to undefined.
function add(a, b = 1) {
return a + b;
}
add(1, 2); // 3
add(1, 1); // 2
add(1); // 2
add(1, undefined); // 2
Use rest parameters (...) as the last parameter in function, then it will receive all remaining actual parameters in an Array. If there's no remaining parameters, it will be empty array.
function doSomething(x, ...y) {
// do something
}
doSomething(1, 2, 3);
// x = 1, y = [2, 3]
doSomething(1);
// x = 1, y = []
It looks like rest operator, but is its opposite.
ES5 | ES6 |
---|---|
[1, 2].concat(more) | [1, 2, ...more] |
list.push.apply(list, [3, 4]) | list.push(...[3, 4]) |
a = list[0], rest = list.slice(1) | [a, ...rest] = list |
console.log(1, 2, 3) | console.log(...[1, 2, 3]) |
Array.prototype.slice.apply(document.querySelectorAll('div')) | [...document.querySelectorAll('div')] |
It is a shorthand for a function assigned to the method's name.
var obj = {
foo() {
/* code */
},
bar() {
/* code */
}
};
var obj2 = {
* g() {
var index = 0;
while(true)
yield index++;
}
};
var obj = {
foo: function() {
/* code */
},
bar: function() {
/* code */
}
};
var obj2 = {
g: function*() {
var index = 0;
while(true)
yield index++;
}
};
ES6
ES5
When the property key is as same as the name of the variable that specifies the property value, then you can use property shorhands.
const x = 4;
const y = 1;
const obj = { x, y };
// is equivalent to
const obj = { x: x, y: y };
// it can work well with `destructuring`
const obj = { x: 4, y: 1 };
const { x, y } = obj;
console.log(x); // 4
console.log(y); // 1
It allows you to write an expression wrapped in squared brackets instead of regular property name
const name = 'name'
const user = { [name]: 'Haku' }
console.log(user)
// { name: 'Haku' }
function getType(type) {
return {
[type]: {
message: `${type} type`,
date: new Date()
},
};
}
var name = 'name'
var user = {}
user[name] = 'Haku'
console.log(user)
// { name: 'Haku' }
function getType(type) {
var obj = {};
obj[type] = {
message: type + ' type',
date: new Date()
};
return obj;
}
ES6
ES5
// Example from MDN
function Person() {
var that = this;
that.age = 0;
setInterval(function growUp() {
// The callback refers to the
// `that` variable of which
// the value is
// the expected object.
that.age++;
}, 1000);
}
var person = new Person();
Ref: No binding of this
// Example from MDN
function Person(){
this.age = 0;
setInterval(() => {
// |this| properly refers to
// the person object
this.age++;
}, 1000);
}
var p = new Person();
Compare with traditional function expression
var bob = {
_name: 'Bob',
_friends: ['Haku'],
printFriends() {
this._friends.forEach(f =>
console.log(
`${this._name} knows ${f}`
)
);
}
};
bob.printFriends();
// Output: Bob knows Haku
var bob = {
_name: 'Bob',
_friends: [],
printFriends: function () {
this._friends.forEach(function (f) {
console.log(
this._name + ' knows ' + f
);
}, this);
}
};
bob.printFriends();
// Output: Bob knows Haku
ES6
ES5
// Normal syntax
var add = (a, b) => {
return a + b;
};
// Without curly braces,
// the expression body
// will be returned.
var add = (a, b) => a + b;
// Normal syntax
// on single parameter
var toUpper =
(string) => string.toUpperCase();
// Single parameter
// without parentheses
var toUpper =
string => string.toUpperCase();
// Function without parameters
// must have parentheses
var sayHi =
() => console.log('Hi');
// returning an object
// must use parentheses.
var getObj =
() => ({})
console.log(typeof () => {});
// SyntaxError
console.log(typeof (() => {}));
// Output: "function"
const Car = () => {};
new Car();
// TypeError:
// Car is not a constructor
The source of this is an important distinguishing aspect of arrow functions:
Loop over iterable objects (Arrays, strings, Maps, Sets, etc.)
const arr = ['a', 'b'];
for (const [index, element] of arr.entries()) {
console.log(`${index}. ${element}`);
}
// Output:
// 0. a
// 1. b
const map = new Map([
[false, 'no'],
[true, 'yes'],
]);
for (const [key, value] of map) {
console.log(`${key} => ${value}`);
}
// Output:
// false => no
// true => yes