- Destructuring Assignment
- Arrow Functions
- Blocks
- Let && Const
- Template Literals
- Object Literals
- Spread Operator
- Classes
- Iterators
- Generators
- Symbols
- Promises
- Maps
- Weak Maps
- Sets
- Weak Sets
- Proxies
- Number
- Array
- Object
- Strings
- Modules
Destructuring assignment
allow us to assign properties of arrays or objects to variables.
var obj = {
foo: 'Mr.Foo',
bar: 'Mr.Bar'
}
var { foo } = obj // var foo = obj.foo
var { foo: bar } = obj // var bar = obj.foo
var { foo = 'default' } = {} // var foo = ({}).foo || 'default'
var { foo, bar } = obj // var foo = obj.foo; var bar = obj.bar
var { foo } = {} // var foo = undefined
var { foo: { bar: deep } } = { foo: { bar: 'bar' } } // deep = 'bar'
var { foo: { bar } } = {} // ERROR - {}.foo.bar does not exits
var [a,b] = [6,3] // var a = [6,3][0]; var b = [6,3][1]
var [a, ,c] = [6,9,3] // var a = [6,9,3][0]; var c = [6,9,3][2]
var [a,b] = [b,a] // var a = [b,a][0]; var b = [b,a][1]
// Parameter with default value.
var foo = function (bar = 2) {
console.log(bar)
}
foo() // 2
foo(3) // 3
// Parameter with default value object.
var foo = function (bar = {a: 1, b: 2}) {
console.log(bar)
}
foo() // {a: 1, b: 2}
foo({a: 3}) // {a: 3}
// Parameter object with default values.
var foo = function ({a = 1, b = 2}) {
console.log(a)
console.log(b)
}
foo() // ERROR - No default when object is not provided.
foo({}) // 1, 2
foo({a: 3}) // 3, 2
// Parameter object (with default values) and default value.
var foo = function ({a = 1, b = 2} = {}) {
console.log(a)
console.log(b)
}
foo() // 1, 2
foo({}) // 1, 2
foo({a: 3}) // 3, 2
Arrow function
is a shorter syntax for the common function expression.
The cool thing about it is that it doesn't bind its own this, arguments, super or new.target.
var increment = (value) => {
return value 1
}
increment(3) // 4
var increment = (value) => value 1 // Remove the {} from the function body.
increment(3) // 4
var increment = value => value 1 // Removed the () from the value parameter.
increment(3) // 4
// The return statement needs to be wrapped on '()'.
var foo = () => ({
value: 3
})
foo() // { value : 3 }
// "this" is bound to the scope.
this.bar = 3
// ES5
function foo() {
return bar
}
foo() // Error - bar undefined
// ES6
var foo = () => this.bar
foo() // 3
Blocks
are the way to create the common Immediately Invoked Function Expression (IIFE).
// ES5
// In order to have a block scope, we would use
// IIFEs (Immediately Invoked Function Expression).
(function IIFE () {
// Begin block scope
var foo = 'Mr.Foo'
// End block scope
})()
foo // Reference Error
// ES6
// Use {} let or const for block scope
{
// Begin block scope
var zed = 'Mr.Zed'
let foo = 'Mr.Foo'
const bar = 'Mr.Bar'
// End block scope
}
zed // Mr.Zed
foo // Reference Error
bar // Reference Error
Let
and Const
are alternative ways to var
.
Although both let
and const
are block-scoped (instead of function scoped) a variable declared with let
can be reassigned as for const
is not possible to reassign.
let foo = 'Mr.Foo'
// Let variables:
// - are block-scoping (i.e. they live in their defined block.)
// - can be reassigned.
function func (flag) {
if(flag) {
// new block scope
let foo = 'NewFoo'
return foo
// end block scope
}
return foo
}
func(true) // NewFoo
func(false) // Mr.Foo
const foo = 'Mr.Foo'
// Const variables:
// - are block-scoping.
// - can't be reassigned (assignment is immutable.)
foo = 'NewFoo' // ERROR - No new assignment allowed.
// An interesting example
const bar = { a : 3 }
bar = { b : 7} // error - No new assignment allowed.
bar.a = 7 // OK - We are updating a property, not the assignment.
- 2ality - Variables and Scoping in ECMAScript 6
- MDN - Const and MDN - let
- PonyFoo - ES6 Let, Const and the “Temporal Dead Zone” (TDZ) in Depth
Template literals
allows us to easily build string values with expressions on it.
`ES6 Template String`
// String wrapped into ""
`Double "quote"` // Double "quote"
// String wrapped into ''
`Single 'quote'` // Single 'quote'
// Multiple line
`Multiple
Line`
`${1 2}` // 3
const foo = 'MrFoo'
`Hello ${foo}` // Hello MrFoo
const bar = () => 'MrBar'
`Hello ${bar()}` // Hello MrBar
const mr = (template, ...expressions) => {
// template is an Array broke at the interpolations
// e.g. for `foo {$a} bar {$b}`
// template = ['Dear ', ' and ', '']
return template.reduce((result, current, index) => {
return `${result}Mr.${expressions[index - 1]}${current}`
})
}
const foo = 'Foo'
const bar = 'Bar'
mr`Dear ${foo} and ${bar}` // Dear Mr.Foo and Mr.Bar
Object literals
are a simple lists of key properties with a pair value (i.e. key:value).
// Property value shorthand
const foo = 'Mr.Foo'
{
// Because the property 'foo' has the
// same name as the const 'foo'
// no need to write { foo: foo }
foo
}
// Computed properties
{
// [ value to compute to property ] : value
[ 1 3 ] : 'Number 4'
}
// Method definition
{ bar () {
// Code for function bar
}
}
The spread operator
allow us to expanded an expression into multiple variables (i.e. destructuring assignment) or multiples variables (i.e. array literals) or multiple arguments (i.e. function calls.)
[foo, , ...rest] = [1,2,3,4,5]
console.log(foo) // 1
console.log(rest) // [3,4,5]
function foo (...parameters) {
// parameters is an Array
// with all parameters.
console.log(parameters)
}
foo(1,2,3) // [1,2,3]
foo([1,2,3],4) // [[1,2,3],4]
// We can name some parameters
function foo (bar, ...parameters) {
// bar is the first parameter.
// parameters is an Array containing
// the remaining parameters.
console.log(bar, parameters)
}
foo() // undefined, []
foo(1) // 1, []
foo(1,2,3) // 1, [2,3]
[1, ...[2,3], 4] // [1,2,3,4]
function foo (a,b,c) {
console.log(a,b,c)
}
foo(...[1,2,3]) // 1, 2, 3
Javascript is a functional programming language.
However, the concept of Classes
in ES6 is just syntax sugar on top of prototypal inheritance.
The goal is to make the language more obvious to programmers coming from other paradigms (e.g. OO).
class Counter {
constructor () {
this.count = 0
}
increment () {
this.count
}
decrement () {
this.count--
}
static isNil (counter) {
return counter.count === 0
}
}
let counter = new Counter()
counter.increment() // 1
counter.increment() // 2
counter.decrement() // 1
Counter.isNil(counter) // false
// We now can use the keyword "extends" to easily "inherit" from other "classes".
// Not forgetting that this is only syntax sugar to ES5 prototype terminology.
class Temperature extends Counter {
constructor () {
// The super keyword identifies our base class "Counter".
super()
}
decrement () {
if(this.count > 0) {
super.decrement()
}
}
}
let termo = new Temperature()
termo.decrement() // 0 // no decrement because "count" was already 0
termo.increment() // 1
termo.decrement() // 0
Iteration is the new mechanism offer by ES6 to traversing data.
An iterable
is a data structure responsable to enable data access to the public, and it does that by implementing a method whose key is Symbol.iterator
(which is a factory for iterators.)
const iterable = {
[Symbol.iterator] () {}
}
// An iterator is a pointer for traversing the elements of a data structure.
// Under the wood JS has a method called @@iterator,
// By using the well-known Symbol.iterator we can assign an iterator to this method.
// @@iterator is called once, whenever an object needs to be iterated (e.g. for..of loop)
// @@iterator will be asked for an iterator.
// The returned iterator is then used to obtain the values of the object.
// The iterator protocol has to define how to get values out of an object.
// We need to define an @@iterator that satisfies that.
// The iterator protocol indicates that we must have an object with a 'next' method.
// The 'next' method has no arguments and returns an object with two properties:
// * done - true if the sequence has end, false otherwise.
// * value - the current item in the sequence
const iterable = {
[Symbol.iterator]() {
const items = ['f', 'o', 'o']
const iterator = {
next () {
return {
done: items.length === 0,
value: items.shift()
}
}
}
return iterator
}
}
for(let item of iterable) {
console.log(item)
// f
// o
// o
}
- MDN - Iteration Protocols
- 2ality - Iterables and iterators in ECMAScript 6
- ExploringJS - Iterables and iterators
- PonyFoo - ES6 Iterators in Depth
Generators
are created by declaring a generator function, which returns a generator object (e.g. g) that can then be iterated using Array.from(g)
, [...g]
, or for value of g
.
// We use the symbol * to mark a function as a generator and 'yield' to emit an element sequence.
function* generator () {
yield 'f'
yield 'o'
yield 'o'
}
[...generator()] // ['f', 'o', 'o']
// Generator object follow both iterable and iterator protocol.
var g = generator()
// It is an iterable because if has na @@iterator.
typeof g[Symbol.iterator] === 'function' // true
// It is an iterator because if has the .next method.
typeof g.next === 'function' // true
// The iterator for a generator is the generator itself.
g[Symbol.iterator]() === g // true
[...g] // ['f','o','o']
Array.from(g) // ['f', 'o', 'o']
for(let item of g) {
console.log(item)
// 'f'
// 'o'
// 'o'
}
// Whenever the 'yield' expression is reached, the value is emitted
// by the iterator and the function execution is suspended.
function* generator () {
yield 'foo'
console.log('and')
yield 'bar'
}
var foo = generator()
foo.next() // emits { value: 'f', done: false } and suspends
foo.next() // logs 'and', emits { value: 'bar', done: false }, and suspends
foo.next() // emits {value: undefined, done: true } and finishes
// Whenever .next() is called on a generator, there's four events that can suspend the execution:
// * yield - emits the next value in the sequence
// * return - returns the last value in the sequence
// * throw - stops the execution in the generator entirely
// Use 'yield*' to delegate to other generator function.
function* generator () {
yield* 'foo'
}
console.log([...generator()]) // ['f','o','o']
Symbols
are just a new primitive type in Javascript.
typeof Symbol() // 'symbol'
// They are simple tokens that can be used as unique IDs.
// We can create a new symbol by using the function Symbol().
const ID = Symbol()
// Every symbol returned by Symbol() is unique.
Symbol() === Symbol() // false
// Symbol() has an optional string-value parameters,
// which represents the symbol description.
// This description is used to convert the symbol to a String.
const symbol = Symbol('aSymbol')
String(symbol) // 'Symbol(aSymbol)'
const KEY = Symbol()
const obj = {
[KEY]: 'Value'
}
console.log(obj[KEY]) // 'Value'
const CAR_BMW = Symbol('BMW')
const CAR_AUDI = Symbol('Audi')
const CAR_MERCEDES = Symbol('Mercedes')
// We can add symbols at run-time with Symbol.for(key) and Symbol.keyFor(symbol)
// We can lookup key in runtime-wide on symbol registry.
// If a symbol with that key exists then it would be returned.
// If no symbol exists, then on would be created.
// Therefore, Symbol.for(key) is idempotent.
Symbol.for('foo') === Symbol.for('foo') // true
// Symbol.keyFor(symbol) returns the key to which the symbol was associated with.
const BAR = Symbol.for('bar')
console.log(Symbol.keyFor(BAR)) // 'bar'
A promise
is defined as "a proxy for a value that will eventually become available".
Although they can be use to both synchronous and asynchronous code flows, they are though for async flows.
We can chain a Promise with the method .then()
, which has two parameters:
- onFulfilled - Callback to be executed on promise success
- onRejected - Callback to be executed on promise fail
fetch('foo').then(
function onFulfilled (response) {
// Handle success response.
console.log(response)
},
function onRejected () {
// Handle error.
console.log('error')
}
)
We can create promises from scratch by using new Promise(resolver)
, where resolver
parameter is the method used to resolve the promise.
The resolver
parameter has two arguments:
- resolve - Callback to when the promise is fulfilled
- rejected - Callback to when the promise is rejected
new Promise(resolve => resolve()) // promise is fulfilled
new Promise((resolve, reject) => reject()) // promise is rejected
// Resolving a promise with a value.
new Promise(resolve => resolve('foo'))
.then(result => console.log(result)) // foo
// Resolving a promise with an exception.
new Promise((resolve, reject) => reject(new Error('Connection Timeout')))
.then(null, reason => console.log(reason)) // Error: Connection Timeout
It allow us to wait for a set of promise to resolve.
Promise.all([
new Promise(resolve => resolve('foo')),
new Promise(resolve => resolve('bar'))
]).then(response => console.log(response)) // ['foo', 'bar']
// If a single promise is rejected, the Promise.all is entirely rejected.
Promise.all([
Promise.reject(),
new Promise(resolve => resolve('foo'))
]).then(() => console.log('All Resolved'), () => console.log('All Rejected')) // 'All Rejected'
A Map
object is a new data structure is JavaScript with a simple key/value map. Any value (i.e. primite or objects) can be used as both key and value.
var map = new Map()
// We can use any object that follows the iterable protocol.
// e.g. ['key', 'value']
var map = new Map([
['foo', 'Mr.Foo'],
['bar', 'Mr.Bar']
])
console.log(map) // Map { 'foo' => 'Mr.Foo', 'bar' => 'Mr.Bar' }
// We can use the spread operator to have the opposite effect.
console.log([...map]) // [ [ 'foo', 'Mr.Foo' ], [ 'bar', 'Mr.Bar' ] ]
var map = new Map()
// Use primitive as values.
map.set('foo', 'Mr.Foo') // Map { 'foo' => 'Mr.Foo' }
map.set(3, 'Mr.3') // Map { 'foo' => 'Mr.Foo', 3 => 'Mr.3' }
// Because `keys` are unique, when setting a key that is already defined,
// it will override the existing one.
map.set('foo', 'Mr.Bar') // Map { 'foo' => 'Mr.Bar', 3 => 'Mr.3' }
// Use objects as values.
map.set(() => 'key', 'Value') // Map { [Function] => 'Value' }
map.set({}, 'Value') // Map { {} => 'Value' }
map.set(new Date, 'Value') // Map { 2017-03-16T16:37:15.488Z => 'Value' }
map.set(Symbol, 'Value') // Map { Symbol => 'Value' }
var map = new Map([['foo', 'Mr.Foo']])
console.log(map.has('foo')) // true
console.log(map.has('bar')) // false
var map = new Map([['foo', 'Mr.Foo'], ['bar', 'Mr.Bar']])
// Using .delete()
map.delete('bar')
console.log(map) // Map { 'foo' => 'Mr.Foo' }
// Using .clear(), which deletes everything
map.clear()
console.log(map) // Map { }
var map = new Map([['foo', 'Mr.Foo'], ['bar', 'Mr.Bar']])
// Use .entries() to iterate over the map.
console.log(map.entries()) // MapIterator { [ 'foo', 'Mr.Foo' ], [ 'bar', 'Mr.Bar' ] }
// Use .keys() to iterate over the map keys.
console.log(map.keys()) // MapIterator { 'foo', 'bar' }
// Use .values() to iterate over the map values.
console.log(map.values()) // MapIterator { 'Mr.Foo', 'Mr.Bar' }
We can think of WeakMaps
as a sub set of Maps.
WeakMaps are not iterable, i.e. they don't follow the iterable protocol.
var map = new WeakMap()
// Every key must be an object.
map.set('foo', 'Mr.Foo') // TypeError: Invalid value used as weak map key
// This enables the map keys to be garage collected
// when they're only being referenced as WeakMap keys.
// This is useful when we want to store data that will
// eventually be lost, e.g. DOM nodes.
// We can pass an iterable to populate the WeakMap.
var foo = new Date()
var bar = () => {}
var map = new WeakMap([[foo, 'Mr.foo'], [bar, 'Mr.bar']]);
// .has()
console.log(map.has(foo)) // true
// .get()
console.log(map.get(bar)) // 'Mr.Bar'
// .delete()
map.delete(foo);
console.log(map.has(foo)) // false
Sets
are another data structure introduced by ECMAScript 6. It works for arbitrary values.
var set = new Set()
set.add('foo') // Set { 'foo' }
set.add('bar') // Set { 'foo', 'bar' }
// .size
set.size // 2
// .keys()
var keysIterator = set.keys() // SetIterator { 'foo', 'bar' }
keysIterator.next().value // 'foo'
keysIterator.next().value // 'bar'
// .values()
var valuesIterator = set.values()
valuesIterator.next().value // 'foo'
valuesIterator.next().value // 'bar'
// .entries()
// Returns a new Iterator object containing an array of [value, value]
// for each element in the Set, in insertion order.
var entriesIterator = set.entries()
console.log(entriesIterator.next().value) // ['foo', 'foo']
console.log(entriesIterator.next().value) // ['bar', 'bar']
// .add()
set.add('zed') // Set { 'foo', 'bar', 'zed' }
// .has()
set.has('zed') // true
// .delete()
set.delete('zed') // Set { 'foo', 'bar' }
A WeakSet
is set that it allows its elements being garbage-collected.
var set = new Set()
// .add()
set.add('foo') // Set { 'foo' }
// .has()
set.has('foo') // true
// .delete()
set.delete('foo') // Set { }
Proxies
allows us to intercept and customize behaviour on operations performed on objects (e.g. getting of setting properties). They are a metaprogramming feature.
// Proxies allows us to defined behaviour whenever
// the properties of a target object are accessed.
var target = {}
// The handler object is used to configure traps for our Proxy.
var handler = {}
var proxy = new Proxy(target, handler)
// Proxy works as a simple pass-through to the target.
proxy.foo = 'Mr.Foo'
console.log(target.foo) // 'Mr.Foo'
console.log(target.bar) // undefined
Traps allow us to intercept interactions on target, as long as those interactions happen through the Proxy.
// Let's define a Trap on the handler.get().
var handler = {
// The handler.get() method is a trap for getting a property value.
get: function (target, property, receiver) {
// We run our Trap code, i.e. console.log.
console.log(`Got property ${property}`)
// Then return the value as .get() will usually do.
return target[property]
}
}
var target = { foo: 'Mr.Foo' }
var proxy = new Proxy(target, handler)
console.log(proxy.foo)
// 'Got property foo'
// 'Mr.Foo'
Revocable proxies are the same as Proxies, with the difference that they can be revoke.
var target = {}
var handler = {}
var { proxy, revoke } = Proxy.revocable(target, handler)
proxy.foo = 'Mr.Foo'
console.log(proxy) // { foo: 'Mr.Foo' }
// By revoking a Proxy we disable any operations on the Proxy.
// After revoking, any operations on the Proxy will throw an error.
revoke()
proxy.foo // TypeError: Cannot perform 'get' on a proxy that has been revoked
Number
is the same Javascript object that words as a wrapper of a numeric value. However, with ECMAScript 6 there's a couple of new things.
// Binary Literals.
// 0b prefix for binary literals.
console.log(0b001) // 1
console.log(0b010) // 2
// Octal Literals.
// 0o prefix for octal literals.
console.log(0o001) // 1
console.log(0o010) // 8
// .isNaN()
// Determines if the provided value is NaN and its type is Number.
Number.isNaN(NaN) // true
Number.isNaN(0/0) // true
Number.isNaN('a' * 'b') // true
Number.isNaN(1) // false
Number.isNaN('foo') // false
Number.isNaN(undefined) // false
// .isFinite()
// Determines if the provided value is a finite number.
Number.isFinite(Infinity) // false
Number.isFinite(-Infinity) // false
Number.isFinite(NaN) // false
Number.isFinite(0) // true
Number.isFinite(0b001) // true
Number.isFinite(0o001) // true
Number.isFinite('0') // false, would be true with global isFinite('0')
Number.isFinite(null) // false, would be true with global isFinite(null)
// .parseInt()
// Parses a String to an integer in the specified radix.
// Has exactly the same functionality as the global parseInt().
Number.parseInt('10', 2) // 2
Number.parseInt('10', 8) // 8
Number.parseInt('10', 10) // 10
// .parseFloat()
// As for parseInt, Number.parseFloat() has exactly the same
// functionality as the global parseFloat().
// .isInteger()
// Determines if the provided value is a finite number
// without a decimal part.
Number.isInteger(Infinity) // false
Number.isInteger(-Infinity) // false
Number.isInteger(NaN) // false
Number.isInteger(undefined) // false
Number.isInteger(null) // false
Number.isInteger(0) // true
Number.isInteger(2.75) // false
Number.isInteger(-5) // true
Number.EPSILON
// Which represents the smallest positive value.
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/EPSILON
Number.MAX_SAFE_INTEGER
// Which represents the largest integer that
// can be safely and precisely represented in JavaScript.
Number.MIN_SAFE_INTEGER
// Which represents the smallest integer that
// can be safely and precisely represented in JavaScript.
Number.isSafeInteger
// Returns true for any integer between
// [MIN_SAFE_INTEGER, MAX_SAFE_INTEGER].
With ES6 Arrays
have now a couple of new methods. We will explore those in the example bellow.
// .from()
// Creates a new Array from an array-like or iterable object.
var foo = ['f', 'o', 'o']
Array.from(foo) // ['f', 'o', 'o']
Array.from('foo') // ['f', 'o', 'o']
// .of()
// Create a new Array from a variable number of arguments.
Array.of(3) // [3]
// Which differs from:
Array(3) // [ , , ]
Array.of(3, 'foo', {}) // [ 3, 'foo', {} ]
// Which is equal to:
Array(3, 'foo', {}) // [ 3, 'foo', {} ]
// .copyWithin(target, start, end)
// Copies part of an array (start-end)
// to another location (target) in the same array.
Array(1, 2, 3, 4).copyWithin(2) // [ 1, 2, 1, 2 ]
Array(1, 2, 3, 4).copyWithin(2, 1) // [ 1, 2, 2, 3 ]
Array(1, 2, 3, 4).copyWithin(2, 0, 1) // [ 1, 2, 1, 4 ]
// .fill(value, start, end)
// Fills all elements in the array (start-end)
// with the provided value.
Array(3).fill('foo') // [ 'foo', 'foo', 'foo' ]
Array(3).fill('foo', 1) // [ , 'foo', 'foo' ]
Array(3).fill('foo', 1, 2) // [ , 'foo', ]
// .find(callback)
// Returns the first element in the array
// that satisfies the condition.
function isEven(value) {
return value % 2 === 0
}
Array(1,2,3,4).find(isEven) // 2
// .findIndex(callback)
// Returns the index of the first element in the array
// that satisfies the condition.
Array(1,2,3,4).findIndex(isEven) // 1 <- index of element 2
// .keys()
// Returns a new Array Iterator that contains the keys
// for each index in the array.
var iterator = [ 'foo', 'bar', 'zed' ].keys()
console.log(iterator.next().value) // 0
console.log(iterator.next().value) // 1
console.log(iterator.next().value) // 2
// .values()
// Returns a new Array Iterator that contains the values
// for each index in the array.
var iterator = [ 'foo', 'bar', 'zed' ].values()
console.log(iterator.next().value) // 'foo'
console.log(iterator.next().value) // 'bar'
console.log(iterator.next().value) // 'zed'
// .entries()
// Returns a new Array Iterator that contains the pairs
// [ key, value ] for each index in the array.
var iterator = [ 'foo', 'bar', 'zed' ].entries()
console.log(iterator.next().value) // [ 0, 'foo' ]
console.log(iterator.next().value) // [ 1, 'bar' ]
console.log(iterator.next().value) // [ 2, 'zed' ]
There were a couple of changes in JavaScript Objects
, mainly:
- Object.assign - Copies the values of all enumerable properties from on or more source objects to the target and returns the target's object reference.
- Object.is - Determines if two objects are the same.
- Object.getOwnPropertySymbols - Returns an array with all the properties that are symbols.
- Object.setPrototypeOf - Sets the prototype of the specified object to another prototype.
// .assign(target, ...sources)
Object.assign({}, { foo: 'Mr.Foo' }, { bar: 'Mr.Bar' }) // { foo: 'Mr.Foo', bar: 'Mr.Bar' }
Object.assign({ foo: 'Mr.Foo' }, { foo: 'Foo' }) // { foo: 'Foo' }
// .is(value1, value2)
Object.is([], []) // false
Object.is({}, {}) // false
Object.is(0, -0) // false
Object.is('foo', 'foo') // true
Object.is(null, null) // true
// .getOwnPropertySymbols(obj)
var objectSymbols = Object.getOwnPropertySymbols({
[Symbol('foo')]: 'Mr.Foo',
[Symbol('bar')]: 'Mr.Bar'
}) // [ Symbol(foo), Symbol(bar) ]
console.log(objectSymbols.length) // 2
console.log(objectSymbols[0]) // Symbol(foo)
// .setPrototypeOf(obj, prototype)
var foo = {}
Object.setPrototypeOf(foo, null)
console.log(Object.getPrototypeOf(foo)) // null
As for Object, Strings
have had some updates.
// .startsWith(searchString[, position])
// Determines if a string beings with the specified characters
// at the specific position.
'foo & bar'.startsWith('foo') // true
'foo & bar'.startsWith('bar') // false
'foo & bar'.startsWith('bar', 6) // true
// .endsWith(searchString[, position])
// Determines if a string ends with the specified characters
// at the specific position.
'foo & bar'.endsWith('bar') // true
'foo & bar'.endsWith('foo') // false
'foo & bar'.endsWith('foo', 3) // true
// .includes(searchString[, position])
// Determines if a string can be founds within another string.
'Mr.foo'.includes('foo') // true
'Mr.foo'.includes('bar') // false
'Mr.foo'.includes('Mr', 2) // false
// .repeat(count)
// Returns a new string containing the specified
// number (count) of copies.
'foo'.repeat(2) // 'foofoo'
// [Symbol.iterator]
// Returns a new Iterator object that iterates over
// each code character or its code point representation.
var iterator = 'ABC'[Symbol.iterator]()
console.log(iterator.next().value); // 'A'
console.log(iterator.next().value); // 'B'
console.log(iterator.next().value); // 'C'
var iterator = 'A\uD835\uDC68B\uD835\uDC69C\uD835\uDC6A'[Symbol.iterator]()
console.log(iterator.next().value); // 'A'
console.log(iterator.next().value); // '\uD835\uDC68'
console.log(iterator.next().value); // 'B'
// .codePointAt(position)
// Returns the unicode of the character at the specified position.
'Foo'.codePointAt(0) // 70
// .fromCodePoint(num1[, ...[, numN]])
// Returns the string created by the specified
// sequence of code points.
String.fromCodePoint(70, 111, 111) // 'Foo'
// .normalize([form])
// Returns a Unicode Normalization Form of a give string.
// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/normalize
Modules
is the JavaScript standard module system strongly influenced by CommonJS. With ES6 modules we now have the terminology of export
and import
which we will explored in the examples bellow.
// Default export
export default 'foo'
export default NaN
export default { foo: 'Mr.Foo' }
export default () => 'Mr.Foo'
// Naming export
export var foo = 'Mr.Foo'
var foo = 'Mr.Foo'
var bar = 'Mr.Bar'
export { foo, bar }
var foo = 'Mr.Foo'
export { foo as myFoo }
// Default export with naming
var api = {
foo: 'Mr.Foo',
bar: 'Mr.Bar'
}
export default api
// Default import
// export default 'foo'
import * from '_moduleName_'
// Naming import
// export var foo = 'Mr.Foo'
import { foo } from '_moduleName_'
// export { foo: 'Mr.Foo', bar: 'Mr.Bar' }
import { foo, bar } from '_moduleName_'
// export { foo as myFoo }
import { myFoo } from '_moduleName_'