- https://javascript.info/import-export
- https://stackoverflow.com/questions/37200080/how-to-export-imported-object-in-es6
export let months = ['Jan', 'Feb', 'Mar','Apr', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
export const MODULES_BECAME_STANDARD_YEAR = 2015;
export function sayHi() { ... }
export class User {
constructor(name) {
this.name = name;
}
}
// named export
export class User {...}
import {User} from ...
// default export
export default class User {...}
import User from ...
import {sayHi, sayBye} from './say.js';
sayHi('John'); // Hello, John!
sayBye('John'); // Bye, John!
import * as say from './say.js';
say.sayHi('John');
say.sayBye('John');
number
bigint
string
boolean
null
undefined
object
symbol
function
try {
// stuff
} catch(err) {
// stuff
if (err instanceof ValidationError) {
// stuff
} else {
throw err // re-throw it
}
} finally {
// stuff
}
// generic error with custom message
throw new Error("Negative water")
// custom error class
class ValidationError extends Error {
constructor(message) {
super(message)
this.name = "ValidationError"
}
}
/**
* Returns x raised to the n-th power.
*
* @param {number} x The number to raise.
* @param {number} n The power, must be a natural number.
* @return {number} x raised to the n-th power.
*/
function pow(x, n) {
...
}
function sayHi() {
alert("Hello")
}
sayHi() // "Hello"
let sayHi2 = sayHi
sayHi2() // "Hello"
function Calculator() {
this.read = function() {
this.a = +prompt('a?', 0);
this.b = +prompt('b?', 0);
};
this.sum = function() {
return this.a + this.b;
};
this.mul = function() {
return this.a * this.b;
};
}
let calculator = new Calculator();
calculator.read();
alert( "Sum=" + calculator.sum() );
alert( "Mul=" + calculator.mul() );
- Constructor functions • Link
push(...items)
addsitems
to the end.pop()
removes the element from the end and returns it.shift()
removes the element from the beginning and returns it.unshift(...items)
addsitems
to the beginning.
let [firstName, surname] = "Ilya Kantor".split(' ')
// unwanted elements of the array can be discarded via an extra comma
let [firstName, , title] = ["Julius", "Caesar", "Consul", "of the Roman Republic"]
// works with any iterable on the right-side
let [a, b, c] = "abc" // ["a", "b", "c"]
let [one, two, three] = new Set([1, 2, 3])
// default values
let [name = "Guest", surname = "Anonymous"] = ["Julius"];
let options = {
title: "Menu",
width: 100,
height: 200
};
let {title, width, height} = options;
// default values
let {width = 100, height = 200, title} = options;
// rest pattern "..."
let {title, ...rest} = options;
title // "Menu"
rest // { height: 200, width: 100 }
// nested
let options = {
size: {
width: 100,
height: 200
},
items: ["Cake", "Donut"],
extra: true
};
let {
size: { // put size here
width,
height
},
items: [item1, item2], // assign items here
title = "Menu" // not present in the object (default value is used)
} = options
alert(title) // Menu
alert(width) // 100
alert(height) // 200
alert(item1) // Cake
alert(item2) // Donut
// functions
function({
incomingProperty: varName = defaultValue
...
})
// example
let options = {
title: "My menu",
items: ["Item1", "Item2"]
}
function showMenu({
title = "Untitled",
width: w = 100, // width goes to w
height: h = 200, // height goes to h
items: [item1, item2] // items first element goes to item1, second to item2
}) {
alert( `${title} ${w} ${h}` ) // My Menu 100 200
alert( item1 ) // Item1
alert( item2 ) // Item2
}
// 1. while
while (condition) {
// stuff
}
// 2. do..while
do {
// stuff
} while (condition)
// 3. for (;;)
for (let i = 0; i < 3; i++) {
i // 0, then 1, then 2
}
// 4a. for..in (with array)
let arr = ["Apple", "Orange", "Pear"]
for (let i in arr) {
i // 0, then 1, then 2
alert( arr[i] ) // Apple, Orange, Pear
}
// 4b. for..in (with object)
let user = { name: "John" }
for (let key in user) {
key // "name"
user[key] // "John"
}
// 5a. for..of (with array or string)
for (let char of "Hello") {
alert(char); // "H", then "e", then "l", etc
}
// 5b. for..of (with object)
for (const [k, v] of Object.entries(obj)) {
console.log(k, v);
}
// 6. forEach (with array)
let arr = ["Apple", "Orange", "Pear"]
arr.forEach((item, index, arr) => {
item // 65, then 44, then 12
index // 0, then 1, then 2
arr // ["Apple", "Orange", "Pear"]
});
// break, continue
break
continue
// loop labelling for specific break/continue
outer: for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (!input) break outer;
}
}
let user = {
name: "John",
age: 30,
"likes birds": true
}
/**
* Set
*/
user.name = "Jane"
user["likes birds"] = false
/**
* Set key via variable (method 1)
*/
let fruit = "apple"
let bag = {}
bag[fruit] = 5
bag // { apple: 5 }
/**
* Set key via variable (method 2)
*/
let bag = {
[fruit]: 5
}
bag // { apple: 5 }
/**
* Set key and value directly (shorthand syntax)
*/
let name = "John", age = 1;
let user = {
name,
age
}
user // { name: "John", age: 1 }
/**
* Set key to a function (method 1)
*/
user = {
sayHi: function() {
alert("Hello")
}
}
/**
* Set key to a function (method 2, shorthand)
*/
user = {
sayHi() {
alert("Hello")
}
}
/**
* Get
*/
user.name // "John"
user["name"] // "John"
/**
* Using `this` within an object
* Note:
* Arrow functions have no `this`, it will reference the outer "normal" function
*/
let user = {
name: "John",
age: 30,
sayHi() {
alert(this.name) // `this` is the "current object"
}
}
user.sayHi() // "John"
/**
* Check if key exists (method 1)
* Use triple equal, bcos double equal will match against null (false positive)
*/
object.exampleKey === undefined // true|false
/**
* Check if key exists (method 2)
*/
"exampleKey" in object // true|false
/**
* Delete
*/
delete user.name
delete user["likes birds"]
/**
* Iterate through keys with for..in loop
*/
let user = { name: "John" }
for (let key in user) {
key // "name"
user[key] // "John"
}
- Object keys are "ordered in a special fashion". Integer keys are sorted, others appear in creation order • Link
- When an object variable is copied - the reference is copied, the object is not duplicated • Link
- Clone and merge objects with
Object.assign
. If object contains nested objects, must "deep clone", or uselodash.cloneDeep
library • Link - Two objects are equal only if they are the same object • Link
- Understanding
this
in methods and objects • Link
Symbol
is a primitive type for unique identifiers. Link
JavaScript symbols are entirely different from Ruby. Don't confuse them.
/**
* Symbols are guaranteed to be unique.
* Even if we create many symbols with the same description, they are different values.
* The description is just a label that doesn’t affect anything.
*/
let id1 = Symbol("id")
let id2 = Symbol("id")
alert(id1 == id2) // false
/**
* Symbols don’t auto-convert to a string
*/
let id = Symbol("meow")
alert(id) // TypeError: Cannot convert a Symbol value to a string
alert(id.toString()) // "Symbol(meow)"
alert(id.description) // "meow"
/**
* Global symbols
*/
// read from the global registry
let id = Symbol.for("id") // if the symbol did not exist, it is created
// read it again (maybe from another part of the code)
let idAgain = Symbol.for("id")
// the same symbol
alert( id === idAgain ) // true
// reverse of `Symbol.for(key)`
let sym = Symbol.for("id")
alert( Symbol.keyFor(sym) ) // "id"
- Symbols allow us to create “hidden” properties of an object, that no other part of code can accidentally access or overwrite Link
- Symbol keys in object are skipped by for..in loop Link
Decorator is simply a way of wrapping one piece of code with another - literally “decorating” it. Guide
class Example {
@log
sum(a, b) {
return a + b;
}
}
const e = new Example();
e.sum(1, 2);
// Arguments: 1,2
// Result: 3
function log(target, name, descriptor) {
const original = descriptor.value;
if (typeof original === 'function') {
descriptor.value = function(...args) {
console.log(`Arguments: ${args}`);
try {
const result = original.apply(this, args);
console.log(`Result: ${result}`);
return result;
} catch (e) {
console.log(`Error: ${e}`);
throw e;
}
}
}
return descriptor;
}
function(...args) {
console.log(`Arguments: ${args}`);
}
When importing in ES6, all functions become available by default. To make a function private to prevent importing, use the “function-as-variable” hack, because variables cannot be imported.
// assigning function definition to a variable.
// same outcome, same usage, but sort of like a "private method", instead of "public method".
let myFunc = () => {}