- Arrow Function
- let, const and Block Scoping
- Modules
- Classes
- Template Literals
- Spread / Rest Operator
- New Statments
- Array Methods
- Number Methods
- Object Methods
- Collections
- Iterables & Iterators
- Generators
- Symbols
- Proxy
- Reflect
- Destructuring Assigment
- Object Literal Enhancements
- Subclassable Built-ins
- Tail Call Optimization (TCO)
- Getter
- Setter
- String Methods
- Binary and Octal Literals
Shorter syntax for function expression with simplified scope rules.
// Basic syntax
( /* Function Parameters */ ) => { /* Function Body */ }
// No parameters
() => {}
// Multiple parameters
( param1, param2, paramN ) => {}
// Destructuring parameters
( [x, y], [1, 2] ) => {}
// Default parameters
( x = 1 ) => {}
// Rest parameters
( ...rest ) => {}
/**
* implicit return: mustaches and return keyword are
* optional when returning single expression
*/
() => expression
// For returning objects wrap object inside parenthesis
() => ({ x: 1 })
// With single parameter parenthesis are optional
singleParam => {}
- Arrow function can't be used as constructor function ( i.e. can't be instantiated with
new
keyword ). - Arrow function can't be used as generator.
- Arrow function doesn't have a
prototype
property. - Arrow function doesn't bind
this
,argument
,new.target
,super
. - Arrow function has lexical
this
meaning it inheritsthis
from the enclosing context. - Arrow function with
call()
,apply()
,bind()
ignores the passed context and only consider the passed arguments. - Arrow function ignores Strict mode rules regard
this
. - Arrow function doesn't have
arguments
object, it inherits it from the enclosing regular function otherwiseRefrenceError
is thrown.
// [ Note 3 ]
let arrow = () => {};
console.log( arrow.prototype ); // undefined
// [ Note 4 ]
let obj = {
fn: function () {
let arrow = () => { return this }
return arrow();
}
};
obj.fn(); // obj not Window
// [ Note 6 ]
var addOne = () => { return this.x + 1 }
var y = { x: 0 }
addOne.call( y ); // NaN not 1 as this === Window
// [ Note 7 ]
let strict = () => { 'use strict'; return this; } // Window not undefined
let loose = () => { return this; } // Window
// [ Note 8 ]
let fn = function ( x ) {
console.log( arguments[0] ) // x
let arrow = ( y ) => {
console.log( arguments[0] ) // x not y
}
arrow( 1 );
}
fn( 0 );
Arrow functions are used usually as callback functions, non-method functions or generally at situation where the dynamic binding of this
and arguments
isn't needed, for example:
- Use as
Array
functional programming methods iterator function. - Use as callback in timing functions.
- Use as Promises callback functions.
- Use as simpler IIFE.
// [ Item 1 ]
let arr = [1, 2, 3, 4, 5];
let odd = arr.filter( item => item % 2 !== 0 ); // [1, 3, 5]
// [ Item 2 ]
setTimeout(() => {
console.log( 'I\'m simple :)' )
}, 100);
// [ Item 3 ]
let p = new Promise((resolve, reject) => {
// Do your magic
});
p.then(data => {
// Play with data
});
// [ Item 4 ]
;(() => {
// IIFE without passed arguments
})();
;(global => {
// IIFE with passed arguments
})(window);
Used to create a global-scoped or block-scoped variable whose refrence can be re-assigned but it can't be re-declared in the same scope.
let identifier [= expression]; // Assignment is optional
let
creates global-scoped & block-scoped variable contrary tovar
that creates global-scoped & function-scoped only.let
doesn't create properties on global object contrary tovar
.let
allows only a single declaration for a sepecific identifier within the same scope. redeclaring the same variable created bylet
within the same scope throws anSuntaxError
.let
assignment (a.k.a: intialzation) is optional meaninig you can do thislet x;
.let
gets hoisted but it can't be accessed within the Temporal Dead Zone[1] (a.k.a: TDZ) means you can't reference the identifier before or within the declaration statement orRefrenceError
is thrown;
- [1] Temporal Dead Zone : The period between scope starting position untill the declaration statement position.
// [ Item 1 ]
let x = 0; // global-scoped
function fn() {
let y = 1; // function-scoped also block-scoped
if ( y === 1 ) {
let z = 2; // block-scoped
}
}
// [ Item 2 ]
let x = 0;
window.x; // undefined not 0
// [ Item 3 ]
let x = 0;
let x = 1; // SyntaxError
let y = 1;
if ( true ) {
let y = 2; // Totally valid
}
// [ Item 5 ]
let x = 0;
let fn = function () {
return x;
let x = 1; // Error below asserts that x is hoisted
};
fn() // RefrenceError
- Use
let
whereever you need to re-assign the same identifier to a different value, with loops for instance, otherwise useconst
.
The same as let
with some differences. It is used to create a global-scoped or block-scoped variable whose refrence can't be re-assigned and it can't be re-declared in the same scope.
const IDENTIFIER = expression; // Assignment is a must
const
creates global-scoped & block-scoped variable contrary tovar
that creates global-scoped & function-scoped only, same aslet
.const
doesn't create properties on global object contrary tovar
, same aslet
.const
allows only a single declaration for a sepecific identifier within the same scope. redeclaring the same variable created byconst
within the same scope throws aSyntaxError
. re-assigment of the same identifier at any scope throws aTypeError
.const
allows you to delete/write/edit the assigned object.const
assignment (a.k.a: intialzation) is a must meaninig you can't do thisconst x;
contrary tolet
.const
gets hoisted but it can't be accessed within the Temporal Dead Zone (a.k.a: TDZ) means you can't reference the identifier before or within the declaration statement orRefrenceError
is thrown;
- Common practice when using
const
: capitalize all identifier letters and in case multiple words identifier use_
as separator.
// [ Item 1 ]
const X = 0; // global-scoped
function fn() {
const Y = 1; // function-scoped also block-scoped
if ( Y === 1 ) {
const Z = 2; // block-scoped
}
}
// [ Item 2 ]
const X = 0;
window.X; // undefined not 0
// [ Item 3 ]
const X = 0;
const X = 1; // SyntaxError
X = 1; // TypeError: re-assigment is not allowed
const Y = 1;
if ( true ) {
Y = 2; // TypeError: re-assigment is not allowed
const Y = 2; // Totally valid
}
// [ Item 4 ]
const ARR = [1, 2];
ARR.push(3); // Valid: ARR = [1, 2, 3]
delete ARR[0]; // Valid: ARR = [undefined, 2, 3]
ARR[0] = 'ONE'; // Valid: ARR = ['ONE', 2, 3]
// [ Item 6 ]
const X = 0;
const FN = function () {
return x;
const X = 1; // Error below asserts that x is hoisted
};
FN() // RefrenceError
- Use
const
whereever you don't need to re-assign the same identifier to a different value, otherwise uselet
.
Promise is the eventual result of async operation.
- Resolver: Function that defines
Promise
logic. - Thenable: Object with a
then
method, it may be aPromise
object or user defined object. - Pending:
Promise
status when it doesn't achieve any result yet. - Settlement:
Promise
status when it achieves any result (success/fail). - Fulfillment:
Promise
has succeeded/resolved. - Fail/Reject:
Promise
is rejected/failed.
[https://i.stack.imgur.com/idOX8.png]
/**
* Promise constructor consists of 3 simple parts as following:
*
* [1] : Async operation.
* [2] : Success condition to resolve returned data from async operation.
* [3] : Fail condition to reject the promise.
*/
const
promise = new Promise(( resolve, reject ) => {
// [1]
const
data = '';
// [2]
data && resolve( data );
// [3]
!data && reject( new Error('Error: Promise Rejected!') );
});
/**
* @param {function} successHandler receives `[[PromiseValue]]` property value as its argument if `[[PromiseStatus]]` is resolved.
* @param {function} errorHandler receives promise passed error as its argument if `[[PromiseStatus]]` is rejected.
* @return Promise Object.
*/
promise.then( successHandler, errorHandler );
/**
* @param {function} errorHandler receives promise passed error as its argument if `[[PromiseStatus]]` is rejected.
* @return Promise Object.
*/
promise.catch( errorHandler );
/**
* @param {array} iterable array of promises
* @return Promise Object.
*/
Promise.all( iterable )
/**
* @param {array} iterable array of promises
* @return Promise Object.
*/
Promise.race( iterable )
/**
* @param {*} arg value, promise, thenable.
* @return Promise Object.
*/
Promise.resolve( arg )
/**
* @param {*} arg value passed when promise is rejected.
* @return Promise Object.
*/
Promise.reject( arg )
- Inside
Promise
constructor body any error thrown is treated as the rejection value. then
: method used to register callback to receive fulfillment value and/or the reason why the promise is rejected.- For chainable
then
, each onesuccessHandler
's argument equals to the previousthen
return value. - When a promise is rejected the first
catch
method fires its callback with the promise error as its argument. catch
method doesn't stop further code execution.- each
then
method throws its error to the nextcatch
method in the chain. Promise.catch( errorHandler )
=Promise.then( null, errorHandler )
.- Whenever possible try to make promise rejection value as instance of
Error
for debugging purposes. Promise.all
: if only one promise in the collection is rejected then the return promise[[PromiseStatus]]
will berejected
.Promise.race
: the first settled promise is the one who defines the returned promise[[PromiseStatus]]
&[[PromiseValue]]
.
export default expression
export { name1, name2 as alias, name3 as default, ... }
export let multiple, names
- Only one default value can be exported from the same script.
- The name of the default export can be omitted (i.e. you can export anonymous function).
import defaultName from './module'
import * as namespace from './module'
import { name1, name2 as alias, ... } from './module'
import defaultName, * as namespace from './module'
import defaultName, { name1, name2 as alias, ... } from './module'
import './module'
- Importing something that wasn't exported will fail.
- If your module code will run once you can ignore all naming rules and just
import './filename'
.
Syntactic sugar for prototypal inheritance in JavaScript.
Reserved keyword used to define a constructor class.
class ClassName {
// ...
}
class
name binding inside its scope isconst
binding andlet
binding outside.class
can't be called directly as functions do (i.e.ClassName()
throws).
Method used once inside a class to define properties and methods on it.
class ClassName {
constructor() {
this.name = 'ClassName';
}
}
constructor
method can't be used withstatic
keyword.constructor
method can only be used once inside class.- Methods defined outside
constructor
is set on the class prototype.
Reserved keyword used when deriving subclasses from a superclass.
class Parent {
// ...
}
class Child extends Parent {
// ...
}
- Methods defined on the super class are accessible by its subclasses.
Reserved keyword used inside subclasses or object literals as a reference for their superclass, or their prototypes in case of object literals.
class Parent {
constructor(kind) {
this.kind = kind
}
}
class Child extends Parent {
constructor(childName, parentKind) {
super(parentKind);
this.name = childName;
}
sayName() {
console.log( 'My Name is ' + this.name + ' and I\'m ' + this.kind );
}
}
let baby = new Child('John', 'Human');
baby.sayName(); // My Name is John and I'm Human
const
Parent = {
kind: 'Human'
},
Child = {
name: 'John',
sayName() {
console.log( 'My Name is ' + this.name + ' and I\'m ' + super.kind )
}
};
Object.setPrototypeOf(Child, Parent);
Child.sayName(); // My Name is John and I'm Human
- You can't access superclass properties/methods before invoking
super()
method first inside subclass constructor.
Reserved keyword used to define (static methods) methods accessible only by classes themselves not their instances.
class Parent {
static sayName(name) {
console.log(name);
}
}
Parent.sayName('Doe'); // Doe
const parentName = new Parent();
parentName.sayName('Doe'); // TypeError
- Static methods are reserved for their respective class and can't be accessed inside its instances.
Special type of string literals with the capability of holding embedded expressions and optionally parsed by custom function called tag function.
let string = `contents`;
JavaScript expressions that can be parsed at runtime inside template literals and initiated by ${ expression }
.
let greeting = 'Hello';
console.log( `${greeting} Developer!` );
Custom function used to control parsing template literal.
let parseResult = TAG_FUNCTION_NAME`contents`;
const
name = 'Neo',
HTMLEscaped = escape`<div>I'm ${name}</div>`
/**
* Custom function used to escape HTML angles
*
* @param {array} strings
* Array of template literal string parts with `row` property containing
* array of the same values but without parsing backslash escape sequences.
* @param {array} subs
* Array containing all substitution expressions parsed values.
* @return {string} the newly parsed template literal contents.
*/
function escape( strings, ...subs ) {
const results = [];
strings = strings.map((string) => {
let escapedString = string.replace(/</i, '<').replace(/>/i, '>')
return escapedString;
});
for ( const i of strings ) {
results.push( i, subs[strings.indexOf(i)] || '' )
}
return results.join('');
}
console.log( HTMLEscaped ); // <div>I'm Neo</div>
Method used to access template literal string contents without parsing backslash escape sequences (i.e. the source code as you type it in the script file).
console.log(`My name is ${'NEO'}.\n\nand I've no choice`)
// My name is NEO.
//
// and I've no choice
console.log(String.raw`My name is ${'NEO'}.\n\nand I've no choice`)
// My name is NEO.\n\nand I've no choice
Expands and expression in positions where a comma separated list are expected like function call arguments, array elements, destructuring
let x = [3, 4]
let y = [1, 2, ...x] // [1, 2, 3, 4]
let args = [1, 2, 3]
invoke(...args) === invoke(1, 2, 3)
Used to convert function infinte number of arguments into array in function declarations.
function add(...args) {
let total = 0;
args.map((num) => {
total += num;
});
return total;
}
add(1, 2, 3, 4) // 10
Statement used to loop over an iterable object and provide a hook to each one of its property to do something with.
for ( value of iterable ) {
// do some thing using value
}
cont arr = [1, 2, 3]
for (let val of arr) {
val *= 2
console.log(val)
} // 2 4 6
- Array.from
- Array.of
- Array.prototype.fill
- Array.prototype.find
- Array.prototype.findIndex
- Array.prototype.entries
- Array.prototype.keys
- Array.prototype.copyWithin
Method used to create an array from array-like & iterable objects.
Array.from( obj,
mapFunction ?= undefined,
context ?= enclosing context ) // => array of the provided input
let
arrLike = { 0: 'zero', 1: 'one', length: 2 },
iterable = 'iterable',
fn = function () {
let args = Array.from( arguments );
console.log( args )
};
Array.from( arrLike, (val, idx) => (val += ' in digits ' + idx)) // ['zero in digits 0', 'one in digits 1']
Array.from( iterable )// ['i','t','e','r','a','b','l','e']
fn(1, 2) // [1, 2]
Method used to create an array from its passed arguments regardless of their type.
Array.of(elm0[, elem1, ... elemN]) // => array of arguments
Array.of(1, 'string', false, undefined, null, new Date(), {x: 0}, [1]) // [1, "string", false, undefined, null, "3030-01-01:)", {x:0}, [1]]
Method used to change array slots values to the passed value from a starting index to end index.
arr.fill( val,
start ?= 0,
end ?= arr.length ) // => new filled array
[1, 2, 3].fill(0) // [0,0,0]
[1, 2, 3].fill(0, 1) // [1,0,0]
[1, 2, 3].fill(0, 1, 2) // [1,0,3]
[1, 2, 3].fill(0, -1) // [1,2,0]
[1, 2, 3].fill(0, -1, -2) // [1,2,3]
[1, 2, 3].fill(0, -5, -10) // [1,2,3]
Method used to find an first element that passes a test function in a given array.
arr.find( testFN(element, index, arr),
context ?= undefined ) // => the first matched element value
let
arr = [1, 2, 3, 4],
testFN = (elem) => elem % 2 === 0;
// find the first even numer in the array
arr.find(testFN); // 2
Method used to find an first element index that passes a test function in a given array.
arr.findIndex(testFN(element, index, arr),
context ?= undefined) // => the first matched element value
let
arr = [1, 2, 3, 4],
testFN = (elem) => elem % 2 === 0;
// find the index of the first even numer in the array
arr.findIndex(testFN); // 1
Method used to create array iterator from key/value pairs of the provided array.
arr.entries() // => Array Iterator
let it = [1, 2, 3, 4].entries();
it.next().value; // [0, 1]
it.next().value; // [1, 2]
it.next().value; // [2, 3]
it.next().value; // [3, 4]
Method used to create array iterator from indexes of the provided array.
arr.keys() // => Array Iterator
let it = [1, 2, 3, 4].keys();
it.next().value; // 0
it.next().value; // 1
it.next().value; // 2
it.next().value; // 3
Method used to copy array or array-like elements from one position to another inside the same array.
arr.copyWithin( targetIndex,
start ?= 0,
end ?= arr.length ) // => new formated array
let
arr = [1, 2, 3, 4, 5],
arrLike = { 0: 1, 1: 2, 2: 3, length: 3 }
arr.copyWithin(0, 3) // => [4, 5, 3, 4, 5]
[].copyWithin.call(arrLike, 0, 2) // => { 0: 3, 1: 2, 2: 3, length: 3 }
- Number.isNaN
- Number.isInteger
- Number.isFinite
- Number.parseInt
- Number.parseFloat
- Number.MAX_SAFE_INTEGER
- Number.MIN_SAFE_INTEGER
- Number.isSafeInteger
- Number.EPSILON
Checks if a value is NaN.
Number.isNaN(value)
Number.isNaN(0/0) // => true
Number.isNaN(NaN) // => true
Number.isNaN(true) // => false
Number.isNaN('NaN') // => false
Checks if a value is integer.
Number.isInteger(value)
Number.isInteger(1) // => true
Number.isInteger('1') // => true
Number.isInteger(1.1) // => false
Checks if a value is finite number.
Number.isFinite(value)
Number.isFinite(1) // => true
Number.isFinite(2e64) // => true
Number.isFinite(Infinity) // => false
Number.isFinite(NaN) // => false
Number.isFinite(1/0) // => false
parses a value as integer.
Number.parseInt(value)
Number.parseInt(1.2) // => 1
Number.parseInt('1.99') // => 1
Number.parseInt(NaN) // => NaN
Number.parseInt(Infinity) // => NaN
parses a value as floating point number.
Number.parseFloat(value)
Number.parseFloat(1.1) // => 1.1
Number.parseFloat('1.99') // => 1.99
Number.parseFloat(NaN) // => NaN
Number.parseFloat(Infinity) // => Infinity
Returns the minimum safest interger.
Number.MIN_SAFE_INTEGER // => -(2 ** 53 - 1)
Returns the maximum safest interger.
Number.MAX_SAFE_INTEGER // => 2 ** 53 - 1
Checks if a number is a safe integer meaning it falls between and including -(2 ** 53 - 1) & (2 ** 53 - 1).
Number.isSafeInteger(value)
Returns the smallest possible positive number.
Number.EPSILON // => 2 ** -52
- Object.prototype.proto
- Object.is()
- Object.setPrototypeOf()
- Object.assign()
- Object.getOwnPropertySymbols()
Object property that refrence its constructor prototype obejct.
instance.__proto__
let
x = function () {},
y = {};
x.__proto__ === x.constructor.prototype === Function.prototype
y.__proto__ === y.constructor.prototype === Object.prototype
Checks equality of its arguments without applying implicit coersion
Object.is(param1, param2)
Object.is(NaN, NaN) // => true
Object.is(NaN, 0/0) // => true
Object.is(0, -0) // => false
Object.is({}, {}) // => false
Define an object as a prototype of other object.
Object.setPrototypeOf(obj, prototype);
const Human = {
kind: 'human'
};
const Man = {
gender: 'Man'
}
const me = {
name: 'Mo'
}
Object.setPrototypeOf(Man, Human);
Object.setPrototypeOf(me, Man);
me // => { kind: 'human', [[gender: 'Man', name: 'Mo']] }
Shallow copies own enumerable properties from one/multiple source object(s) to a traget object.
Object.assign(target, srcObj1, ...)
const
x = { a: 1 },
y = { b: 2 },
z = Object.assign({}, x, y);
z // => { a: 1, b: 2 }
Returns an array of all symbol properties of an object
Object.getOwnPropertySymbols(obj) // => [Symbol(x), ...]
const
obj = {
[Symbol('a')]: 1,
[Symbol('b')]: 2
};
Object.getOwnPropertySymbols(obj) // => [Symbol(a), Symbol(b)]
Map Objects = Objects + super powers :).
new Map([iterable])
/**
* [1] : Creating a map object using constructor args.
* [2] : Creating a map object using `set` method.
*/
// [1]
const
map1 = new Map([['first', 1], [{key: 'object as a key'}, 'object']]);
// [2]
const
map2 = new Map();
map2.set('first', 1);
map2.set({key: 'object as a key'}, 'object');
Map.prototype.size
: Determines number of map object members.Map.prototype.set(key, value)
: Registers a new member in a map object.Map.prototype.get(key)
: Retrieves a value of a map object member.Map.prototype.delete(key)
: Deletes a map object member.Map.prototype.clear()
: Empty map object.Map.prototype.has(key)
: Checks for member existence in a map object.Map.prototype.entries()
: Provides iterable object contaning all members key/value pairs in array format.Map.prototype.keys()
: Provides iterable object contaning all members keys in array format.Map.prototype.values()
: Provides iterable object contaning all members values in array format.Map.prototype.forEach(callbackFn[, thisArg])
: Loops throught each map object member and apply a callback function on it.
var
map = new Map([['first', 1], [{key: 'object as a key'}, 'object'], [3, [1, 2]]]);
map.size // => 3
map.get('first') // => 1
map.has('first') // => true
map.entries() // => [[Entries]] = [['first', 1], [{key: 'object as a key'}, 'object'], [3, [1, 2]]]
map.keys() // => [[Entries]] = ['first', {key: 'object as a key'}, 3]
map.values() // => [[Entries]] = [1, 'object', [1, 2]]
map.delete('first') // => returns `true` and map [[Entries]] = [[{key: 'object as a key'}, 'object'], [3, [1, 2]]]
map.clear() // => map now has no [[Entries]]
const
myMap = new Map();
myMap.set('first', 1);
myMap.set({key: 'object as a key'}, 'object');
myMap.forEach((val, key, obj) => {
console.log(`I'm ${obj} object, I have '${val}' as the value of ${key}`)
})
// I'm [object Map] object, I have '1' as the value of first
// I'm [object Map] object, I have 'object' as the value of [object Object]
Some of the powers of Map objects:
- Map objects are iterable, it can be used with
for ... of
loop. - Map objects has dynamic
size
property to determine number of object members. - Map objects keys can be any type primitive or compound.
- Map objects has direct check for member existence via
has
method.
WeakMap objects are the same as Map objects with the following exceptions:
- WeakMap object keys must be objects.
- WeakMap object members are weakly refrenced meaning if they haven't non refrences they will be garbage collected.
Indexed data structure with unique values, same as arrays but without duplicates.
new Set([iterable])
const
set = new Set([1, 2, 3, 3, 3]);
set // => [[Entries]] : [1, 2, 3]
Set
has the same API as Map
Object above except that set
method is replaced with add
method to add members to the object, also it doesn't have a get
method.
const
set = new Set([1, 2]);
set.add(3) // => [[Entries]] : [1, 2, 3]
// You can't directly access set content.
const
arr = [...set]
arr[0]
- Think of Set behavior as arrays but without the duplications.
- You can't directly access
set
content see above example for accesingset
members.
WeakSet objects are the same as Set objects with the following exceptions:
- WeakSet object values must be objects.
- WeakSet object members are weakly refrenced meaning if they haven't non refrences they will be garbage collected.
- Iterable: Object with
[Symbol.iterator]
method as own property which when called returns an iterator. - Iterator: Object containing
next
method as own property which when called returns object with two properties:value
: Holds current value of the iterator.done
: Boolean defines iteration process end.
/* For Demo Purposes */
const
iterator = {
// ...
next: () => {
// ...
return {
value : /* Any JavaScript value */,
done : /* ture | false */
}
}
},
iterable = {
// ...
[Symbol.iterator]: () => {
// ...
return iterator
}
}
Array
TypedArray
Map
Set
NodeList
- Objects returned from
entries()
,keys()
,values()
methods.
for ... of
loop- Spread Operator
- Destructuring
const arr = [1, 2, 3];
for (elem of arr) {
console.log(elem) // 1, 2, 3
}
const add = (a, b, c) => a + b + c;
add(...arr) // 6
const [a, b, c] = arr;
console.log(a) // => 1
console.log(b) // => 2
console.log(c) // => 3
Functions able to pause/resume its body execution. It returns iterable generator object that can be used to step through execution process. pause/resume points are defined by yield
expression.
function* generator() {
statements;
}
function* gen() {
yield 1;
yield 2;
yield 3;
}
const x = gen();
x.next().value // => 1
x.next().value // => 2
x.next().value // => 3
x.next().value // => undefined
Function that returns unique identifier of symbol
primitive type for each call.
Symbol('optional string value')
- One of the usual practical usages of
Symbol()
function is generate unique identifiers for object properties.
const obj = {
[Symbol()] : 1,
[Symbol('y')] : 2,
[Symbol('z')] : 3,
[Symbol('z')] : 4
}
const
syms = Object.getOwnPropertySymbols(obj),
symZ1 = obj[syms[2]],
symZ2 = obj[syms[3]];
console.log(syms) // => [Symbol(), Symbol(y), Symbol(z), Symbol(z)]
console.log(syms[2]) // => Symbol(z)
console.log(syms[3]) // => Symbol(z)
console.log(symZ1) // => 3
console.log(symZ2) // => 4
Symbol.iterator
Symbol.match
Symbol.replace
Symbol.search
Symbol.split
Symbol.hasInstance
Symbol.isConcatSpreadable
Symbol.unscopables
Symbol.species
Symbol.toPrimitive
Symbol.toStringTag
Symbol.for(key)
Symbol.keyFor(sym)
Method used to define iteration behavior of its owner object.
const obj = {
*[Symbol.iterator]() {
// ...
}
}
const evenIt = {
*[Symbol.iterator]() {
for (let i = 0;; i += 2)
yield i
}
}
/**
* Prints even numbers from start to end numbers.
*
* @param {Number} x starting number.
* @param {Number} y end number.
* @return {void}
*/
const print = (x, y) => {
for (let val of evenIt) {
if (val >= x && val <= y)
console.log(val);
if (val === y)
break;
}
}
print(2, 20)
- Exists as a build-in method on
Array
,TypedArray
,Map
,Set
.
Method used to define if a RegExp object should be treated as a regular expression or just a normal string
regexp[Symbol.match](str)
const re = /a/
'/a/'.startsWith(re) // => TypeError -> Because startsWith() expects re to be a string not RegExp.
// Now when modifying the behavior of `re` as string there will be no errors.
re[Symbol.match] = false
'/a/'.startsWith(re) // => true
Method used to define how String.prototype.replace()
should work.
regexp[Symbol.replace](str, newSubStr) // => true
- This method has usually one practical usage which is defining how
String.prototype.replace()
will work when using subclasses ofRegExp
to form its regular expression patterns.
class MyRegExp extends RegExp {
constructor(ptrn, flags) {
super(ptrn, flags);
}
[Symbol.replace](input, replacement) {
return RegExp.prototype[Symbol.replace].call(this, input, (replacement + ' REPLACEMENT')) // => Every replacement will contain 'REPLACEMENT' now
}
}
const
re = new MyRegExp(/My/, 'i'),
str = 'My ',
newstr = str.replace(re, 'Your');
console.log(newstr); // => 'Your REPLACEMENT'
Method used to define how String.prototype.search()
should work.
regexp[Symbol.search](str)
- This method has usually one practical usage which is defining how
String.prototype.search()
will work when using subclasses ofRegExp
to form its regular expression patterns.
class MyRegExp extends RegExp {
constructor(ptrn, flags) {
super(ptrn, flags);
this.ptrn = ptrn
}
[Symbol.search](str) {
return `Found At : ${str.indexOf(this.ptrn)}`
}
}
const
re = new MyRegExp('My'),
str = 'My',
pos = str.search(re);
console.log(pos); // => Found At : 0
Method used to define how String.prototype.split()
should work.
regexp[Symbol.split](str[, limit])
- This method has usually one practical usage which is defining how
String.prototype.split()
will work when using subclasses ofRegExp
to form its regular expression patterns.
class MyRegExp extends RegExp {
[Symbol.split](str, limit) {
let result = RegExp.prototype[Symbol.split].call(this, str, limit)
return result.reduce((acc, elem) => acc + elem)
}
}
const
re = new MyRegExp('-'),
str = 'a-b-c-d',
res = str.split(re);
console.log(res); // => abcd
Method used to customize the behavior of instanceof
operator.
[Symbol.hasInstance](instance)
- This method has usually one practical usage which is defining how
instanceof
operator will work when defining classes and what objects should be instances of it.
class MyObject {
static [Symbol.hasInstance](ins) {
return ins.toString() === '[object Object]'
}
}
console.log({} instanceof MyObject); // => true
Property with boolean value used to define if the target object (array / array-like) should be spreaded/flattened when used with methods like Array.prototype.concat()
.
obj[Symbol.isConcatSpreadable] = true/false
const
arr = [1, 2, 3],
arrLike = {
length: 2,
0: 'a',
1: 'b'
};
arr[Symbol.isConcatSpreadable] = false;
arrLike[Symbol.isConcatSpreadable] = true;
const x = arr.concat(arrLike)
const y = x.concat(arr)
console.log(x) // => [[1, 2, 3], 'a', 'b']
console.log(y) // => [[1, 2, 3], 'a', 'b', [1, 2, 3]]
Property with object value used to define which own/inherited object properties should be available inside with
statsment.
obj[Symbol.unscopables] = { propName: Boolean, ... }
const
obj = {
a: 0,
b: 1
};
obj[Symbol.unscopables] = {
a: false,
b: true
}
with (obj) {
console.log(a) // => 0
console.log(b) // ReferenceError
}
Function valued property used to define the constructor of the derived objects from their original objects.
[Symbol.species] () { /* code... */ }
- One of the possible usages of
Symbol.species
is make a copy of the built-in objects in JavaScript likeObject
,Array
,Promise
...etc, and add on them your custom implementations without having to polluting the original built-in objects.
class MyArray extends Array {
static get [Symbol.species]() {
return Array
}
isEmpty() {
return this.length === 0
}
}
class MyArray2 extends Array {
isEmpty() {
return this.length === 0
}
}
let arr = new MyArray(1,2,3); // Original objects
let arr2 = new MyArray2(1,2,3); // Original objects
let mapped = arr.map(e => e * 2); // Derived objects
let mapped2 = arr2.map(e => e * 2); // Derived objects
console.log( mapped instanceof MyArray ) // => false
console.log( mapped instanceof Array ) // => true
console.log( mapped2 instanceof MyArray2 ) // => true
console.log( mapped2 instanceof Array ) // => true
Function valued property used to define how JavaScript type coercion should work. it takes one argument which is hint
that can be one of three values string
, number
, default
.
[Symbol.toPrimitive] (hint) { /* code... */ }
let obj = {}
console.log(+obj) // => NaN
console.log(`${obj}`) // => "[oject Object]"
console.log(obj + '') // => "[oject Object]"
obj[Symbol.toPrimitive] = hint => {
switch(hint) {
case 'number':
return 1;
break;
case 'string':
return 'obj';
break;
case 'default':
return true;
break;
}
}
console.log(+obj) // => 1
console.log(`${obj}`) // => "obj"
console.log('' + obj) // => "true"
Function valued property used to define a string description of an object. it's used to customize how the Object.prototype.toString()
method return value.
[Symbol.toStringTag] () { return ... }
class MyClass1 {}
class MyClass2 {
get [Symbol.toStringTag] () {
return 'MyClass2'
}
}
const x = new MyClass1();
const y = new MyClass2();
x.toString() // => "[object Object]"
y.toString() // => "[object MyClass2]"
// ^-------- Tag is now pointing to the return of `@@toStringTag`
Checks for the existence of a specified Symbol
in the global symbols registry and return that Symbol
if it's found or creates it then return it if not found.
Symbol.for(string)
Symbol.for('x') === Symbol.for('x') // => true -> Symbol(x)
Symbol('x') === Symbol('x') // => false
Retrieves the key used to create the global registry symbol if found otherwise undefined
.
Symbol.keyFor(Symbol)
const
sym = Symbol.for('x'),
locSym = Symbol('y'),
it = Symbol.iterator;
console.log(Symbol.keyFor(sym)); // => X - found in the global registry
console.log(Symbol.keyFor(locSym)); // => undefined - local symbol not found on the global registry
console.log(Symbol.keyFor(it)); // => undefined - well-known symbol not found on the global registry
Object used to override/customize default behavior of fundamental operations on other objects.
/**
* Proxy Object.
* @param {*} target target object to operate on
* @param {Object} handler tarps container
* @return {Proxy} Proxy Object
*/
const p = new Proxy(target, handler)
Here are some of the practical usages of the Proxy
object. (VIEW REPO OF THE FOLLOWING EXAMPLES HERE).
- Listening to changes on a specific object.
- Object members type validation.
- Achieving true private members.
- Revoking access to data.
- Intercepting certain operations on objects.
Proxy.revocable()
handler.getPrototypeOf()
handler.setPrototypeOf()
handler.isExtensible()
handler.preventExtensions()
handler.getOwnPropertyDescriptor()
handler.defineProperty()
handler.has()
handler.get()
handler.set()
handler.deleteProperty()
handler.ownKeys()
handler.apply()
handler.construct()
Creates a revocable Proxy
object.
/**
* Creates a revocable Proxy object.
* @param {*} target target object to operate on
* @param {Object} handler tarps container
*
* @return {Object}
* Object with two props `proxy` containing the Proxy Object
* and `revoke` method to terminate the proxy.
*/
Proxy.revocable(target, handler);
let
revocable = Proxy.revocable({}, {
get(target, name) {
return `GET: "${name}" Property`
}
});
let p = revocable.proxy;
console.log(p.a); // => GET: "a" Property
// when calling this method every trap throws a TypeError
revocable.revoke();
console.log(p.a); // => TypeError
Intercepts/Customizes [[GetPrototypeOf]]
operations.
.
/**
* Intercept [[GetPrototypeOf]] Operations.
*
* @param {Object} target => target object to find prototype for.
*
* @return {Object|null}
*
* @exceptions
* + TypeError
* 01. Returned value isn't `null` || `Object`.
* 02. Target object isn't extensible.
*/
handler.getPrototypeOf(target);
let
obj = {},
proto = {},
getProto;
getProtoProxy = target => {
const handler = {
getPrototypeOf(target) {
console.log('[[GetProtoType]] Trapped')
return proto;
}
}
return new Proxy(target, handler);
}
let p = getProtoProxy(obj);
console.log(Object.getPrototypeOf(p)) // => [[GetProtoType]] Trapped {}
handler.getPrototypeOf()
traps any operation that depends on[[GetProtoType]]
internal method which will be one of the following:Object.getPrototypeOf()
Reflect.getPrototypeOf()
Object.prototype.isPrototypeOf
instanceof
__proto__
Intercepts/Customizes Object.setPrototypeOf()
operations.
/**
* Intercept setting `[[Prototype]]` internal property Operations.
*
* @param {Object} target => target object to set prototype for.
* @param {Object} prototype => object to set as prototype for target.
*
* @return {Boolean}
* true if the prototype is set, false otherwise.
*
* @exceptions
* + TypeError
* 01. Target object isn't extensible. So the prototype object should be
* the same as `Object.getPrototypeOf()`
*/
handler.setPrototypeOf(target, prototype);
let
obj = {},
proto = {},
setProtoProxy;
setProtoProxy = (target, proto) => {
const handler = {
setPrototypeOf(target, proto) {
return true
}
};
return new Proxy(target, proto);
};
const p = setProtoProxy(obj, proto);
console.log(Object.setPrototypeOf(p, null)) // => { a: 1 }
handler.setPrototypeOf()
traps any operation that depends on setting[[ProtoType]]
internal property which will be one of the following:Object.setPrototypeOf()
Reflect.setPrototypeOf()
Intercepts/Customizes Object.isExtensible()
operations.
/**
* Intercept `Object.isExtensible()` Operations.
*
* @param {Object} target => target object to check its extensibility.
*
* @return {Boolean}
* true if the object is extensible, false otherwise.
*
* @exceptions
* + TypeError
* 01. `Object.isExtensible(proxy)` !== `Object.isExtensible(obj)`
*/
handler.isExtensible(target);
let
obj = {},
nonExObj = {},
extendProxy;
Object.preventExtensions(nonExObj);
extendProxy = target => {
const handler = {
isExtensible(target) {
console.log('isExtensible is accessed!!');
return Reflect.isExtensible(target);
}
}
return new Proxy(target, handler)
}
let
p1 = extendProxy(obj),
p2 = extendProxy(nonExObj);
console.log(Object.isExtensible(p1)); // => isExtensible is accessed!, true
console.log(Object.isExtensible(p2)); // => isExtensible is accessed!, false
Intercepts/Customizes Object.preventExtensions()
operation.
/**
* Intercept `Object.preventExtensions()` Operation.
*
* @param {Object} target => target object to prevent extensibility for.
*
* @return {Boolean}
* true if the object is extensible, false otherwise.
*
* @exceptions
* + TypeError
* 01. `Object.preventExtensions(proxy)` === Object.isExtensible(proxy)
*/
handler.preventExtensions(target);
let
obj = {},
extendProxy;
extendProxy = target => {
const handler = {
preventExtensions(target) {
console.log('preventExtensions is accessed!!');
return Reflect.preventExtensions(target)
}
}
return new Proxy(target, handler)
}
let p = extendProxy(obj);
console.log(Object.preventExtensions(p)); // => isExtensible is accessed!, true
Intercepts/Customizes Object.getOwnPropertyDescriptor()
operation.
/**
* Intercept `Object.getOwnPropertyDescriptor()` Operation.
*
* @param {Object} target => target object to look for property in.
* @param {String} property => property to get descriptor for.
*
* @return {Object|undefined}
* descriptor object for the property or undefined if it doesn't exist.
*
* @exceptions
* + TypeError
* 01. Return isn't `Object` or `undefined`.
* 02. Return undefined for existed property in non-extensible target
* 03. Return undefined for non-configurable property in target
*/
handler.getOwnPropertyDescriptor(target, property);
let
obj = {a: 1},
obj2 = {c: 2},
describeProxy;
Object.preventExtensions(obj2);
Object.defineProperty(obj, 'b', {configurable: false});
describeProxy = (target, prop) => {
const handler = {
getOwnPropertyDescriptor(target, prop) {
console.log('getOwnPropertyDescriptor is accessed!!');
return undefined;
}
}
return new Proxy(target, handler)
}
let
p1 = describeProxy(obj, 'a'),
p2 = describeProxy(obj, 'b'),
p3 = describeProxy(obj2, 'c');
console.log(Object.getOwnPropertyDescriptor(p1, 'a')) // => Descriptor Object
console.log(Object.getOwnPropertyDescriptor(p2, 'b')) // => TypeError: non-configurable property
console.log(Object.getOwnPropertyDescriptor(p3, 'c')) // => TypeError: non-extensible object
Intercepts/Customizes Object.defineProperty()
operation.
/**
* Intercept `Object.defineProperty()` Operation.
*
* @param {Object} target => target object to look for property in.
* @param {String} property => property to define on target object.
* @param {Object} descriptor => descriptor object for the specified property.
*
* @return {Boolean}
* true if the property is set, false otherwise.
*
* @exceptions
* + TypeError
* 01. Return false in `strict mode`.
* 02. Setting configurable existed property to be non-configurable.
* 03. Adding/modifying non-configurable property that doesn't exist as
* non-configurable.
*/
handler.defineProperty(target, property, descriptor);
let
obj = {a: 1},
defineProxy;
Object.defineProperty(obj, 'b', {configurable: false});
defineProxy = (target) => {
const handler = {
defineProperty(target, prop, descriptor) {
console.log('defineProperty is accessed!!');
return true;
}
}
return new Proxy(target, handler)
}
let p = defineProxy(obj);
console.log(Object.defineProperty(p, 'a', {configurable: false})) // => TypeError
console.log(Object.defineProperty(p, 'd', {configurable: false})) // => TypeError
console.log(Object.defineProperty(p, 'b', {writable: false})) // => Object
Intercepts/Customizes in
operator lookups.
/**
* Intercepts/Customizes `in` operator lookups.
*
* @param {Object} target => target object to look for property in.
* @param {String} property => property to look for in target object.
*
* @return {Boolean}
* true if the property exists, false otherwise.
*
* @exceptions
* + TypeError
* 01. Return false if the property exists.
*/
handler.has(target, property);
let
obj = {a: 1},
hasProxy;
Object.defineProperty(obj, 'b', {configurable: false});
hasProxy = (target) => {
const handler = {
has(target, prop) {
console.log('has is accessed!!');
return true;
}
}
return new Proxy(target, handler)
}
let p = hasProxy(obj);
console.log('a' in p) // => has is accessed!!, true
Intercepts/Customizes a property value.
/**
* Intercepts/Customizes a property value.
*
* @param {Object} target => target object to look for property in.
* @param {String} property => property to look for in target object.
* @param {Object} receiver => proxy object.
*
* @return {*}
* Any value.
*
* @exceptions
* + TypeError
* 01. Return different value for non-writable,
* non-configurable properties.
* 02. Not returning `undefined` if the lookup property has value
* of `undefined` and non-configurable.
*/
handler.get(target, property, receiver);
let
obj = {a: 1},
getProxy;
Object.defineProperty(obj, 'b', {configurable: false, writable:false, value: 2});
Object.defineProperty(obj, 'c', {configurable: false});
getProxy = (target) => {
const handler = {
get(target, prop, proxy) {
console.log('get is accessed!!');
return 1;
}
}
return new Proxy(target, handler)
}
let p = getProxy(obj);
console.log(p.a) // => get is accessed!!, 1
console.log(p.b) // => TypeError
console.log(p.c) // => TypeError
Intercepts/Customizes setting a property.
/**
* Intercepts/Customizes setting a property.
*
* @param {Object} target => target object to look set property on.
* @param {String} property => property name.
* @param {*} value => any value.
* @param {Object} receiver => proxy object.
*
* @return {Boolean}
* True if the assignment process is completed
* successfully, false otherwise.
*
* @exceptions
* + TypeError
* 01. Setting non-writable, non-configurable properties.
* 02. Setting non-configurable property that has value of `undefined`.
* 03. Return false from `set` in `strict mode`.
*/
handler.set(target, property, value, receiver);
let
obj = {a: 1},
setProxy;
Object.defineProperty(obj, 'b', {configurable: false});
Object.defineProperty(obj, 'c', {configurable: false, writable: false, value: 2});
setProxy = (target) => {
const handler = {
set(target, prop, value, proxy) {
console.log('set is accessed!!');
return true;
}
}
return new Proxy(target, handler)
}
let p = setProxy(obj);
p.a = 1; // => set is accessed!!, 1
p.b = 1; // => TypeError
Intercepts/Customizes delete
operator.
/**
* Intercepts/Customizes `delete` operator.
*
* @param {Object} target => target object to look set property on.
* @param {String} property => property name.
*
* @return {Boolean}
* True if the delete process is completed
* successfully, false otherwise.
*
* @exceptions
* + TypeError
* 01. Deleting non-configurable own properties.
*/
handler.deleteProperty(target, property);
let
obj = {a: 1},
delProxy;
Object.defineProperty(obj, 'b', {configurable: false});
delProxy = (target) => {
const handler = {
deleteProperty(target, property) {
if (property in target) {
console.log(`Property ${property} successfully deleted!!!`);
return true
} else {
console.log(`Property ${property} not found on ${target} object`);
return false
}
}
}
return new Proxy(target, handler)
}
let p = delProxy(obj);
delete p.a; // => Property a successfully deleted!!!, true
delete p.b; // => TypeError
Intercepts/Customizes Reflect.ownKeys
operation.
/**
* Intercepts/Customizes `Reflect.ownKeys` operation.
*
* @param {Object} target => target object to look for its own keys.
*
* @return {Boolean}
* Array of own enumerable keys.
*
* @exceptions
* + TypeError
* 01. Return isn't an array.
* 02. Returned array containing values types other than
* `String` & `Symbol`.
* 03. Returned array containing non-configurable own properties.
* 04. Returned array containing non-existence keys of
* non-extensible object.
*/
handler.ownKeys(target);
let
obj = {a: 1},
ownProxy;
Object.defineProperty(obj, 'b', {configurable: false});
ownProxy = (target) => {
const handler = {
ownKeys(target) {
console.log(`ownKeys is accessed!!`);
return ['a', 'b', 'c']
}
}
return new Proxy(target, handler)
}
let p = ownProxy(obj);
console.log(Object.getOwnPropertyNames(obj)); // => ownKeys is accessed!!, ['a', 'b', 'c']
handler.ownKeys
intercepts the following operations:Object.keys()
Object.getOwnPopertyNames()
Object.getOwnPropertySymbols()
Reflect.ownKeys()
Intercepts/Customizes function calls.
/**
* Intercepts/Customizes function calls.
*
* @param {Object} target => target function to intercept its invocation.
*
* @return {*}
* Any value.
*/
handler.apply(target);
let
fn = function () { console.log("I'm not gonna show!!") },
applyProxy;
applyProxy = (target) => {
const handler = {
apply(target, thisArg, argsList) {
console.log(`Function is called`);
}
}
return new Proxy(target, handler)
}
let p = applyProxy(fn);
console.log(p()); // => Function is called
Intercepts/Customizes new
operator.
/**
Intercepts/Customizes `new` operator.
*
* @param {Function} target => constructor function/class.
* @param {Array} argsList => array of the passed arguments to constructor.
* @param {Object} proxy => called proxy constructor.
*
* @return {Object}
*
* @exceptions
* + TypeError
* 01. Return isn't Object.
* 02. Target isn't a valid constructor.
*/
handler.construct(target, argsList, proxy);
let
C = function () {},
constructProxy;
constructProxy = (target) => {
const handler = {
construct(target, argsList, proxy) {
console.log(`Construct is accessed`);
return {}
}
}
return new Proxy(target, handler)
}
let p = constructProxy(C);
console.log(new p()); // => Construct is accessed, Object {}
Built-in object that provide methods for interceptable JavaScript operations.
- It's not a function object.
- Not constructible, it does not have a
[[Construct]]
internal method. (Can't usenew Reflect()
). - Not invokable, it does not have a
[[Call]]
internal method. (Can't be invoke it as a functionReflect()
).
Reflect.apply()
Reflect.construct()
Reflect.defineProperty()
Reflect.deleteProperty()
Reflect.get()
Reflect.getOwnPropertyDescriptor()
Reflect.getPrototypeOf()
Reflect.has()
Reflect.isExtensible()
Reflect.ownKeys()
Reflect.preventExtensions()
Reflect.set()
Reflect.setPrototypeOf()
Here are the API methods equivalent to understand how it works.
Reflect.apply(fn, thisArg, argsArray) <=> Function.prototype.apply.call(Math.floor, undefined, [1.75]);
Reflect.construct(Target, argsList, newTarget) <=> new Target(...argsList);
// Diff: `Reflect` case return Boolean
Reflect.defineProperty(target, property, descriptor) <=> Reflect.defineProperty(target, property, descriptor)
// Diff: `Reflect` case return Boolean
Reflect.deleteProperty(target, property) <=> delete target.property
// Object property accessors in the form of a function.
Reflect.get(target, property, receiver) <=>
// Diff: `Reflect` case return Boolean
Reflect.set(target, property, value, receiver) <=> // Object property accessors in the form of a function.
// Diff: if non-object is set as the target in case of using `Reflect` it will throw a type error.
Reflect.getOwnPropertyDescriptor(target, property) <=> Reflect.getOwnPropertyDescriptor(target, property)
Reflect.getPrototypeOf(target) <=> Object.getPrototypeOf(target)
// same as in operator but it works like a function
Reflect.has(target, property) <=> property in target
// same but target must be an object in `Reflect` or error is thrown
Reflect.isExtensible(target) <=> Object.isExtensible(target)
Reflect.ownKeys(target) <=> Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))
// Return Boolean and target must be object otherwise error is thrown
Reflect.preventExtensions(target) <=> Object.preventExtensions(target)
Reflect.setPrototypeOf(target, prototype) <=> Object.setPrototypeOf(target, prototype)
JavaScript expression that used to assign values from arrays, objects, maps, sets to distinct variables.
/**
* [1] : Using rest parameter to make a sub-array from the main array.
* [2] : Using Object literal enhancement to set values to keys as seprate variables.
* [3] : Setting default values to variables.
* [4] : Swapping values.
* [5] : Ignoring some values in destructuring array.
* [6] : Different variable names for properties values.
* [7] : Computed values with destructuring.
*/
let
g = 16,
h = 17,
key = 'm';
let
[a, b, ...rest] = [1, 2, 3, 4], // [1] a = 1, b = 2, rest = [3, 4]
{c, d} = {c: 6, d: 7}, // [2] c = 6, d = 7
{e = 1, f = 2} = {e: 8, f: 9}, // [3] e = 8, f = 9
[g, h] = [h, g], // [4] g = 17, h = 16
[i, ,j] = [10, 11, 12], // [5] i = 10, j = 12
{k: foo, l: bar} = {k: 13, l: 14}, // [6] foo = 13, bar = 14
{[key]: n} = {m: 15} // [7] n = 15
Object literals now supports setting the prototype at construction time, shorthand assignments, shorthand methods, super calls and computed property names.
const
key = 'key',
prop = 'value',
Prototype = Object.create(null),
obj = {
__proto__: Prototype, // Setting prototype at construction
prop, // Shorthand property for prop: prop
method() {} // Shorthand method for method : function () {}
toString() {
return super.toString(); // Super call is supported
},
[key]: 42 // Computed property naming
};
Built-in objects now can be subclassed, like Array
, Date
, Object
.
class MyArray extends Array {
constructor(...args) {
super(...args);
}
// Adding new methods to my custom Array constructor
isEmpty() {
return this.length === 0
}
}
let arr = new MyArray();
arr.isEmpty() // => true
TCO makes it possible to implement recursive function calls without being worried about call stack overflow.
- TCO is a JavaScript engine implementation feature, it cannot be implemented via a transpiler if the browser does not support it.
- Works only in
strict mode
function a() {
return b() // tail call
}
function b() {
return 'Hello World'
}
a() // => Hello World
Method that's invoked when a property is looked up in certain object.
- Can't have any parameters.
- Can be deleted via delete operator on the related property.
{get propName() {}}
{get [computedProp]() {}}
const obj = {
a: 1,
get b() {
console('b property is looked up!!')
return 2
}
}
obj.b // => b property is looked up!!, 2
Method that's invoked when a property is added to certain object.
- Must have only one parameter.
- Can be deleted via delete operator on the related property.
/**
* Method that's invoked when a property is added to certain object.
*
* @param {*} val Reference to the value setted by user
* @return {void}
*/
{set propName(val) {}}
{set [computedProp](val) {}}
const obj = {
a: 1,
set b(val) {
console('b property is assigned a value')
}
}
obj.b = 2 // => b property is assigned a value
Returns string from the provided unicode code points.
/**
* Returns string from the provided unicode code points.
*
* @param {Number} num Reference to unicode point representing a string.
*
* @return {String}
*
* @exceptions
* + RangeError
* 01. If non valid unicode code point is passed.
*/
String.fromCodePoint(num1, ..., numN)
String.fromCodePoint(65); // => "A"
String.fromCodePoint('_'); // => RangeError
Returns a non-negative integer represents Unicode code point for a string value in the specified position.
/**
* Returns a non-negative integer represents Unicode code point
* for a string value in the specified position.
*
* @param {Number} position Index of the input value to get its code point.
*
* @return {Number|undefined}
* `Number` represents Unicode code point if found `undefined` otherwise.
*/
String.prototype.codePointAt(position)
'AB'.codePointAt(1) // => 65
'AB'.codePointAt(3) // => undefined
Determines if a string starts with the specified characters or not.
/**
* Determines if a string starts with the specified characters or not.
*
* @param {String} string Characters to match.
* @param {Number} [position] Index to start matching from.
*
* @return {Boolean}
* true if there's a match, false otherwise.
*/
String.prototype.startsWith(string, position)
'ABC'.startsWith('A') // => true
'ABC'.startsWith('B') // => false
'BAC'.startsWith('A', 1) // => true
Determines if a string ends with the specified characters or not.
/**
* Determines if a string ends with the specified characters or not.
*
* @param {String} string Characters to match.
* @param {Number} [length] Range to search in.
*
* @return {Boolean}
* true if there's a match, false otherwise.
*/
String.prototype.endsWith(string, length)
'ABC'.endsWith('C') // => true
'ABC'.endsWith('B') // => false
'BAC'.endsWith('A', 2) // => true
Determines if a string is found in other string.
/**
* Determines if a string is found in other string.
*
* @param {String} string Characters to match.
* @param {Number} [position] Index to start searching from.
*
* @return {Boolean}
* true if there's a match, false otherwise.
*/
String.prototype.includes(string, position)
'ABC'.includes('C') // => true
'ABC'.includes('D') // => false
'BAC'.includes('A', 1) // => true
Repeats the string called on for the specified number of times.
/**
* Repeats the string called on for the specified number of times.g.
*
* @param {Number} count Number of times to repeat
*
* @return {String}
* the new string containing the repeats.
*
* @exceptions
* + RangeError
* 01. Negative count number
* 02. Infinity
* 03. Maximum string size
*/
String.prototype.repeat(count)
'ABC'.repeat(1) // => 'ABCABC'
'ABC'.repeat(-1) // => RangeError
Method returns the Unicode Normalization Form of a given string.
/**
* Method returns the Unicode Normalization Form of a given string.
*
* @param {String} [form = 'NFC'] Unicode Normalization Form.
*
* @return {String}
* Unicode Normalization Form of the given string.
*
* @exceptions
* + RangeError
* 01. Provided form isn't supported
*/
String.prototype.normalize(form)
const str = '\u1E9B\u0323';
str.normalize(); // '\u1E9B\u0323'
Method returns the non-parsed string of template literals.
/**
* Method returns the non-parsed string of template literals.
*
* @param {Object} callSite Object containing `raw` property.
* @param {Array} subs Placeholders values.
*
* @return {String}
* non-parsed string.
*
* @exceptions
* + TypeError
* 01. callSite isn't `object` containing `raw` property.
*/
String.raw(callSite, ...subs)
String.raw`template literals`
String.raw({ raw: 'hello\n${x}' }, 'world'); // => "hello\\nworld"
String.raw`'hello\nworld`; // => "hello\\nworld"
Two new numeric literal forms are added for binary (0b or 0B) and octal (0o or 0O).
0b11 // => 3
0B11 // => 3
0o10 // => 8
0O10 // => 8