kdocs
GitHub
Lang - Web
Lang - Web
  • Base
    • Css
    • Javascript
    • Typescript
      • New Project
  • Frameworks
    • Angular
      • Directives
      • Components
      • Templates
        • Bindings
        • Control Flow
        • Variables
      • Signals
      • Pipes
      • Services
        • Dependency Injection
      • Forms
        • Reactive Form
        • Template-Driven Form
      • Router
      • HTTP Client
      • Observables RxJS
      • Testing
        • Components
        • Directives
        • Pipes
        • Services
      • Optimization & Performance
      • Security
Powered by GitBook
On this page
  • Data Types
  • Number
  • String
  • Boolean
  • Symbol
  • Regular Expressions (RegExp)
  • Objects
  • JSON
  • Functions
  • Arrow Function
  • Execution Context
  • Exception Handling
  • Destructuring
  • Array
  • Map
  • Weak Map
  • Set
  • Weak Set
  • Iterables and Iterators
  • Classes
  • Proxy and Reflect
  • Modules
  • Promises
  • Generators
  • Async\Await
  • Garbage Collector
  • Registering Performance
  1. Base

Javascript

Data Types

The types are divided in primitives and objects.

Primitives

Primitive types are Immutable

  • number

  • string

  • boolean

  • symbol

  • object

  • undefined

Objects

Are values that represent a memory reference.

Anything that is not a primitive IS an object.

Wrapper

() can change the type data.

Number

Is a primitive and immutable, internally represented by IEEE 754 and is 64 bits.

Can handle values:

  • Decimal,

  • Octonal 0o | 0O,

  • Binary 0b | 0B,

  • Hexadecimal 0x | 0X.

Binary Operators

When using binary representation.

  • | Binary OR

  • & Binary AND

  • ^ Binary XOR

  • ~ Binary Negation

  • << Binary Shift Left

  • >> Binary Shift Right

  • >>> Binary Shift Right with Sign

Convertion Number -> String

(Number).toString( (10 | 16 | 2 | 8) )

Convertion String -> Number

All of these will convert a number in string to its value in number.

  • ~~string: [This is the binary operator, and will double invert]

  • +string

  • string - 0

  • string * 1

  • string / 1

With the exception of +:

  • "10" + 0 will do the concatanation

Decimal Operation residue

Doing math operation in decimals may result in weird results, due to residues due to rouding.

This happens because of the IEEE 754 number representation.

You can then use _lodash libraries for calculations, if you need decimals precision with calculations.

String

Are primitive and immutable, internally represented by Unicode UTF-16.

String Literals

`
This is a literal created string
and they can support multiline
and also code injection with ${var_name}
`

Usefull string functions

.includes(substring): Checks for subtrings in the string.

.startsWith(substring): Checks for substring at the beginning of the string.

.endsWith(substring): Checks for substring at the end of the string.

.localeCompare(otherString): Do comparison of strings and returns -1, 0 or 1, ideal for sort.

.match(RegExp): Return parts of the string based on the RegExp.

.search(RegExp): Return the firts position in the string found by the RegExp.

  • Similar to .indexOf() but with RegExp.

.replace((RegExp | string), string): Return a new string, with replaced data.

.slice(InitialIdx, FinalIdx): Return part of the string parameters are [InitialIdx, FinalIdx).

  • FinalIdx could be negative, which will then count backwards.

.padStart(string) | .padEnd(string): Fill the string with char at the beginning or end.

.trim() | .trimLeft() | .trimRight(): Remove empty spaces.

Boolean

Are primitive and immutable, represented by true and false.

If created using the new Boolean() constructor they will be of type object.

Also new Boolean(false) will be created as true, this happens because of type coersion.

False values in Javascript

There are only 6 cases in javascript are evaluated to false:

!!0          // [Only the Number 0 is evaluated to false]
!!NaN        // [NaN also becomes false]
!!""         // [Only the empty string is evaluated to false]
!!false
!!undefined  // [undefined is also evaluated to false]
!!null       // [null object is evaluated to false]

Anything else will be evaluated to true.

Using logical operators for value attribuition

The return in logical operators are the own operands

  • if 1 || 2 will return 1

  • if true || 5 will return true

  • if false || 10 will return 10

  • if false && 5 will return false

let var = 0 || 2  // -> var = 2
let var = 1 || 2  // -> var = 1
let var = 1 && 2  // -> var = 2
let var = 0 && 2  // -> var = 0

Symbol

Are primitive, unique and immutable, and act as unique keys in objects.

Being uniques, you can never compare them because they will always be different.

They are used internally in for/of, string functions like match, split, replace, and others.

Regular Expressions (RegExp)

Can be used for validating strings, or extracting data from strings.

Usefull RegExp functions

.test(string): Check if passed string has the RegExp pattern.

.exec(string): Return an array of usefull information, with for instance extracted matched strings.

  • To be able to extract, inside the Pattern the section to be extracted must be envolved with (). Ex.: (\w+)@(\w+).com.br

Objects

Is a dynamic collection of properties defined by keys. These keys can ONLY be of type string | Symbol, other types will be converted.

The default primitive Object is considered immutable, because you cannot change its prototype.

undefined and null

undefined ideally means that whatever you are trying to access does not even exist.

null ideally means that the value of something is not set.

Deleting keys

You can delete keys with delete obj.key

Comparing Objects

The comparison of objects is done by reference, thus, you will be comparing their memory reference, which will always be different.

Heritage with (Prototypes)

You can have heritage in objects, just like in classes, with prototypes.

Although the key: value properties inherited by prototypes are NOT SHOWN in console.log or other functions.

Using for in will traverse not only the properties in the current object, but also in the __proto__.

in will check for property existance in the object AND __proto__.

__proto__: The key to access a reference to the object's prototype.

const someAbstractObj = {
    keyA: 'Some value'
}

const someObj = {
    itsKey: 'Another Value',
    __proto__: someAbstractObj
}

Every object created, has a default prototype Object.

This is why when you search for a unexistent key it returns undefined. It will try to access in the current object, if not found, it will go to the object __proto__ and look there. If it doesnt find it again it will again look into __proto__ of that upper object and look there. It will do this until reaches the default prototype object, and then return undefined.

.hasOwnProperty(key): Check if a property key exists in the CURRENT object, it will NOT look in __proto__.

Duplicated properties in own-object and its __proto__, the own-object property is returned and shadows the __proto__ one.

You can access the __proto__ one with own-object.__proto__.property.

Object API

Object.assign(targetObj, {}, {}, ...): To make a shallow copy multiple objects into one.

  • Similar to Spread Operator, thus, having nested objects will implicate in the copies of these properties being copies of its reference, and not hard copies of its data.

const new_obj;

Object.assign(new_obj, { key1: '', key2: '' }, { key3: '' }, ...);

Object.defineProperty(obj, key, { value, ...opts }): Add a property with configuration options.

opts:

  • configurable: That a property be erased. [If a property can be deleted from the object with delete]

  • enumerable: That a property be enumered. [Will not show on console.log, and other funcs that show keys - It will be 'hidden']

  • value: Define the value for this property.

  • writable: That a property have its value altered. [Change values for this property]

let obj = {}

// If you pass only the `value`, the other options will be defaulted to false.
Object.defineProperty(obj, 'some_prop', {
    'value': 'Some value'
});

Object.defineProperty(obj, 'some_prop', {
    'enumerable': true,
    'value': 'Some value',
    'writable': true,
    'configurable': true,
});

Object.preventExtensions(obj): Forbit that the object have new properties, but allow the edit or remove of existent ones.

Object.isExtensible(obj): Check if the preventExtensions is enabled.

Object.seal(obj): Forbit that the object have new properties and remove existent, but allow edit of existent ones.

Object.freeze(obj): Forbit that the object have new properties, edit and remove of existent ones.

JSON

Data types that are accepted values in JSON.

  • number

  • string

  • boolean

  • object

  • array

  • null

Functions

A function is an object that contains executable code.

In Javascript functions are first class, meaning that the can be:

  • Assigned to variables

  • Passed as parameters

  • Returned from other functions

Declaring

Function Declaration

Just like declaring vars with var, the function is always declared in the beginning of the main scope.

  • This is called hoisting.

So you can 'call' this function before declaring it.

function a() {
    ...
}

Function Expression

You attribute it to a variable.

const a = function() {

}

Returning Functions

Functions that are returned from other functions can be instantly called with:

const a = () => {
    return () => {
        return 'Do something';
    }
}

console.log( a()() );
const sum = (a, b) => a + b;
const sub = (a, b) => a - b;

const calculator = (fn) => {
    return (a, b) => {
        return fn(a, b);
    }
}

console.log( calculator(sum)(2, 2) );
console.log( calculator(sub)(2, 2) );

Parameters (Arguments)

You can access the list of arguments by accessing the default variable arguments.

const a = () => {
    console.log(arguments);  // -> { '0': 1, '1': 2, '2': 3 }
}

a(1, 2, 3, ...);

Rest Parameter

Using Spread Operator, but must always be the last parameter declared.

const a = (...args) => {
    ...
}

console.log( a(1, 2, 3, 4) );

this

An implicit variable that always references the object responsible for its invocation.

So, it does not matter if you declare a function in global scope or inside an object, if you call the function inside the object, this will reference the object, and if you call it in global scope it will reference the global scope.

IMPORTANT: this cannot be accessed by functions declared as arrow functions.

area: () => { return this.x * this.y };

const rec = {
    x: 10,
    y: 2,
    area() {
        return this.x * this.y;
    }
}

const area = () => { return this.x * this.y };

const area = function() { return this.x * this.y };
const rec = { x: 10, y: 2, area };

console.log( area() );      // -> undefined
console.log( rec.area() );  // -> 20

getter and setter

It is also possible to defined the getters and setters using .defineProperty().

getter

const rec = {
    x: 10,
    y: 2,
    get area() {
        return this.x * this.y;
    }
}

setter

When working with setter always use the function name different from the property name.

It is common practice to just use _property.

const rec = {
    set x(x) {
        this._x = x;
    }
    set y(y) {
        this._y = y;
    }
    get area() {
        return this._x * this._y;
    }
}

rec.x = 10;
rec.y = 2;
console.log( rec.area() );  // -> 20

call, apply, bind

Using .call() and .apply(), you can invoke a function passing this as parameter.

const area = function() {
    return Math.PI * Math.pow(this.radious, 2);
}

const area2 = function(fn, a, ...) {
    return fn(Math.PI * Math.pow(this.radious, 2)) + a;
}

const circle = {
    radious: 10,
    area,
    area2
}

// Traditional way invoking from the object
console.log( circle.area() );                 // -> 314.12412
console.log( circle.area2(Math.round, 1) );   // -> 315

Using call

function.call(obj, ...args):

  • function: Is the function to be executed.

  • obj: Is the object to give the this context to the function.

  • args: Are additional parameters passed to the function.

console.log( area.call(circle) );                  // -> 314.12412
console.log( area2.call(circle, Math.round, 1) );  // -> 315

Using apply

function.call(obj, [...args]):

  • function: Is the function to be executed.

  • obj: Is the object to give the this context to the function.

  • args: Are additional parameters passed to the function by Array.

console.log( area.apply(circle) );                    // -> 314.12412
console.log( area2.apply(circle, [Math.round, 1]) );  // -> 315

Using bind

Allows encapsulating this inside the function, returning it.

const calcArea = area2.bind(circle);

console.log( calcArea(Math.round, 1) );  // -> 315

new

You can create multiple objects that share the same structure with Constructor Functions.

  • So that you eliminate duplication and have more reusability.

  • By convention they are declared with Capital Letters.

IMPORTANT: Cannot use arrow functions to declare Constructor Functions.

Public properties (the ones that will be returned) will be accessed with this.

const Person = function(name, city, year) {
    this.name = name;
    this.city = city;
    this.year = year;

    // This is private
    let sex = 'whatever';

    // Both of this works
    this.getAge = () => {
        return (new Date()).getFullYear() - this.year;
    }
    this.getAge = function() {
        return (new Date()).getFullYear() - this.year;
    }
}

const person1 = new Person(...);
const person2 = new Person(...);

By declaring the function inside, each person object will have a getAge() of different instance. Thus taking more memory.

To address this...

You declare the getAge() inside the Constructor Funtion prototype.

  • Every function has a property prototype __proto__, linked to the object created by new and only the Constructor Functions use them.

    • [This __proto__ is NOT the same __proto__ from objects heritage]

Person.prototype.getAge = () => {} cannot access this.

const Person = function(name, city, year) {
    this.name = name;
    this.city = city;
    this.year = year;
}
Person.prototype.getAge = function() {
    return (new Date()).getFullYear() - this.year;
}

const person1 = new Person(...);
const person2 = new Person(...);

Now all the instances of Person are inheriting the getAge and sharing its code.

instanceof

With it, it is possible to check if a object was created by a specific Constructor Function, analysing all of its prototype chain.

const data = new Date();

console.log( date instanceof Date )  // -> True

Arrow Function

More simple and direct approuch for declaring functions.

Downside is that they dont have their own this and arguments, so they end up inheriting from the upper closure.

Execution Context

Is the environment where our code is executed.

Composed by:

  • variable object,

  • scope chain

  • this.

The execution context uses an ideia of Stack.

  • Active Execution Context

  • ...

  • Execution Context 2

  • Execution Context 1

  • Global Execution Context

Inside a function, it is possible to access variables outside, by using scope chain. So if the execution cant find a variable in current Context it looks down in the stack.

Every function has a variable this that contains a reference to the object responsible its invocation.

There are examples that using arrow function can help like:

const obj = {
    p1: 10,
    getP1() {
        // In this case, if a normal function declaration was used, it would steel the 'this' reference
        // So since arrow functions dont inject the 'this'....'this' keeps referencing 'obj'
        const fn1 = () => {
            return this.p1;
        }
        return fn1();
    }
}

console.log(obj.getP1());

Closures

Is a function with static scope chain, that is defined the moment a function is created.

Thus, all functions in Javascript are closures.

const v1 = 10;

function fn1() {
    console.log(v1);
}

function fn2(fn1) {
    const v1 = 100;
    fn1();
}

fn2(fn1);  // -> 10

Even though it seems logical that, if fn1 does not find the variable and looks at the upper scope, and then use the v1 = 100, this is wrong.

When fn1 was declared, its closure was defined, so it's fixed that the v1 it will use is the v1 = 10.

Despite static, the scope chain references objects in memory, and so, can be shared between more than one function.

function fn1() {
    let v1 = 10;

    // m1 and m2 share the same scope
    return {
        m1() {
            console.log(++v1);
        },
        m2() {
            console.log(--v1);
        }
    }
}

const obj = fn1();

obj.m1();  // -> 11
obj.m2();  // -> 10

Exception Handling

Any data type can be thrown as an error. It doesnt have to be an Error object.

try {
    throw 'This is just a string';
} catch (e){
    console.log(e);  // -> 'This is just a string'
}

Destructuring

const [ var1 = '', var2 = '' ] = ['thing1', 'thing2'];

const { key1: var1 = '', key2: var2 = '' } = { key1: 'thing1', key2: 'thing2' };

Array

It is just an object that offers operations to access and manipulate its properties.

arr.length: Shows the number of elements inside the Array, but it also considers empty positions.

  • Then, it would show a wrong number of used positions.

  • Thus, avoid using delete to remove elemnts from the Array.

Mutator methods

They modify the Array.

arr.push(el): Add element to the end.

arr.pop(): Remove element from the end.

  • [Also returns the removed element]

arr.unshift(el): Add element at the beginning.

arr.shift(): Remove element at the beginning.

  • [Also returns the removed element]

arr.splice(): Removes, substitutes ou add, one or more elements in a specifig position.

  • [Also return the removed elements]

arr.sort(fn): Sorts the elements according to a function.

  • [-1 and 0 the element stays where it is; 1 it inverts with the other one]

  • [It changes the Array in place, does not return a new one]

arr.reverse(): Reverse the elements order.

arr.fill(): Fills (all or specific interval) of the values with the specified value.

Array iteration

They iterate over Array values.

arr.forEach(fn): Execute the given function for each element.

arr.filter(fn): Returns a new array with only the filtered elements.

arr.find(fn): Returns the first element that returned true in the given function.

arr.some(fn): Returns true if one or more elements returned true in the given function.

arr.every(fn): Returns true if all the elements returned true in the given function.

arr.map(fn): Returns a new array based on the return of the given function.

arr.reduce(fn(result, current) => {}): Return a value based on the return of the given function.

Accessor methods

They return specific information about the Array.

arr.indexOf(): Returns the position of the first found element.

arr.lastIndexOf(): Returns the position of the last found element.

arr.includes(): Return true if the given element exists.

arr.concat(): Returns a new array result of the concatenation.

arr.slice(): Returns part of an array, given a [start, end) position.

arr.join(): Converts the array to a string, joining the elements with a given separator.

Map

Is an object that stores any set of key => value of any kind of data type.

Different from a object that stores only string | Symbol keys.

Atention: May result in memory leaks, if elements are not properly handled.

  • Since references to the keys might be lost, and the values inside the the Map will remain.

const timeUnits = new Map(
    ["second", 1],
    ["minute", 60],
    ["hour", 3600]
);

// Convert the Map back to array
Array.from(timeUnits);

.size: Returns the amount of pairs.

.set(key, value): Add a key => value pair.

.forEach(fn): Iterates over the Map fn(value, key) => {}.

.has(key): Returns true | false if a given key exists.

.get(key): Returns the value | undefined of a given key.

.delete(key): Removes a pair key => value of given key, and returns true | false.

.clear(): Remove all the elements.

Weak Map

Similar to Map, but allows only keys of type object.

  • Maintain the references in a weak way.

    • This is because if the reference to the object, which is a key, is lost, it is not possible anymore to access the value.

  • Not Iterable.

They can be usefull for cache implementations.

const wm1 = new WeakMap();

.set(key, value): Add a key => value pair.

.has(key): Return true if key exists.

.get(key): Return the value of a given key.

.delete(key): Removes a pair given a key.

Set

Is an object that stores unique elements of any kind of data type.

  • Kind of an array.

Does not allow duplicate elements.

Can be used to remove duplicates from arrays.

const charsets = new Set(['Some', 'Other', 'element']);

Array.from(Set): To show the set as array.

.size: Returns the amount of elements.

.add(el): Add an element.

  • If values already exists no error or warning is thrown.

.forEach(fn): Iterates over a Set given a function.

.has(el): Returns true if an element exists.

.delete(el): Removes a element and returns true | false.

.clear(): Removes all the elements.

Weak Set

Is a object similar to Set, but only allow values of type object.

  • Like Weak Map, also maintain weak references.

  • Also not Iterable.

const ws1 = new WeakSet();

.has(el): Return true if element exists.

.add(el): Add objectelement.

.delete(el): Delete element and return true | false.

Iterables and Iterators

Are conventions implemented by Arrays, Maps, Sets and strings, that make them iterable by a iteration protocol.

These Iterable objects are used by:

  • Used by for _ of _.

  • Used by the spread operator.

How an iterator works

const langs = ['A', 'B', 'C'];

const iterator = langs[Symbol.iterator]();

// Will invoke the next element
iterator.next();  -> { value: 'A', done: false }
iterator.next();  -> { value: 'B', done: false }
iterator.next();  -> { value: 'C', done: false }
iterator.next();  -> { value: undefined, done: true }

Creating an Iterator

function createIterator(...args) {
    let i = 0;
    return {
        next() {
            if (i < args.length) {
                return { value: args[i++], done: false }
            }
            else {
                return { value: undefined, done: true }
            }
        }
    }
}

const iterator = createIterator('A', 'B', 'C');

iterator.next();
iterator.next();
iterator.next();
iterator.next();

// This will not work because iterator is not ITERABLE
for (let val of iterator) {
    ...
}

To resolve this...

function createIterable() {
    return {
        [Symbol.iterator]() {
            let i = 0;
            return {
                next() {
                    if (i < args.length) {
                        return { value: args[i++], done: false }
                    }
                    else {
                        return { value: undefined, done: true }
                    }
                }
            }
        }
    }
}

const iterable = createIterable('A', 'B', 'C');

// Now this works
for (let val of iterable){
    ...
}

Classes

Are a special type of function that act as a template for object creation.

  • Classes dont suffer hoisting.

  • They are similar to Constructor Functions.

// Class Declaration
class SomeClass {

}

// Class Expression
const SomeClass = class {

}

They have 3 different member types:

  • constructor

  • prototype methods

  • static methods

constructor

Is invoked at the moment of the class instanciation, and serves to initialize a object.

class Square {
    constructor (side){
        this.side = side;
    }
}

const obj = new Square(4);

prototype methods

They depend on a created instance to be invoked.

class Square {
    ...

    // Prototype method
    toString() {
        return `side: ${this.side}`;
    }
}

const square = new Square(4);

square.toString();

static methods

Dont depend in created instances.

class Square {
    ...

    static fromArea(area) {
        return new Square(Math.sqrt(area));
    }
}

const square = Square.fromArea(16);

extends

Used to create a ``class` hierarchy.

When a class extends a another class, it must call super() before accessing this in the constructor.

class Shape {
    // Notice that the super class can call methods from sub-classes that extends him
    toString() {
        return this.calculateArea();
    }
}

class Square extends Shape{
    constructor (side) {
        super();
        this.side = side;
    }

    calculateArea () {
        return Math.pow(this.side, 2);
    }

    toString() {
        return `side: ${this.side}  area: ${super.toString()}`;
    }
}

class Circle extends Shape{
    constructor (radius) {
        super();
        this.radius = radius;
    }

    calculateArea () {
        return Math.PI * Math.pow(this.side, 2);
    }

    toString() {
        return `radius: ${this.radius}  area: ${super.toString()}`;
    }
}

Proxy and Reflect

Proxy

Capable of intercepting diverse types of operations in a target object.

Trap methods for diverse events related to objects.

  • apply()

  • construct()

  • defineProperty()

  • deleteProperty(target, key)

    • invoked when a property is deleted.

  • get(target, key)

    • invoked when a property is accessed.

  • getOwnPropertyDescriptor()

  • getPrototypeOf()

  • has()

  • isExtensible()

  • ownKeys()

  • preventExtensions()

  • set(target, key, value)

    • invoked when a property is defined in a object.

  • setPrototypeOf()

Ex.: Let's try to make a Factory of objects that will act as arrays.

const createArray = function () {
    return {};
}

const arr = createArray();
arr[0] = 'A';
arr[1] = 'B';
arr[2] = 'C';

Let's suppose that we want to implement a way of having a length.

const createArray = function () {
    // First object is the object to be trapped.
    // Second object is the Traps definitions.
    return new Proxy({}, {
        set(target, key, value) {
            // This length is a created property to hold the length of elements
            target.length = target.length || 0;
            target.length++;

            // We also have to implement this attribution otherwise the object will not save elements
            target[key] = value;
        },
        get(target, key) {
            // Accept only numbers as keys
            if (typeof key === 'string' && key.match(/\d+/))
                return target[key];
        }
        deleteProperty(target, key) {
            if (key in target) {
                target.length--;
                delete target[key];
            }
        }
    });
}

Modules

Imported modules are also hoisted.

Promises

Are objects responsible for modeling asyncronous behaviour, allowing its treatment in a more direct and easy way.

Promise.all()

Promise.all([
    promise1,
    promise2,
    ...
]).then((values) => {
    const [p1Return, p2Return, ...] = values;

    ...
}).catch((e) => {
    ...
});

Promise.race()

Executes multiple promises at the same time, but returns only the first one that finishes.

Promise.race([
   promise1,
   promise2,
   ...
]).then((value) => {
   ...
}).catch((e) => {
   ...
});

Generators

They make possible to pause a function execution, allowing the use of loop event cooperatively.

Used in Iterators.

function* forever() {
    ...
}

const foreverGenerator = forever();

They use the next method to iterate over the available values during the function execution.

  • They return a { value: ..., done: ... }, following the Iterable protocol.

// This executes the function
foreverGererator.next()

When a yield is found, the function execution is paused until the next is invoked again.

  • yield can accept a parameter that will be the value inside the next iterable return.

    • yield parameter.

function* forever() {
    let i = 1;
    while(true) {
        ...
        yield i++;
    }
}

const foreverGenerator = forever();

foreverGenerator.next();  // -> { value: 1, done: false }
foreverGenerator.next();  // -> { value: 2, done: false }
foreverGenerator.next();  // -> { value: 3, done: false }
foreverGenerator.next();  // -> { value: 4, done: false }
  • yield also returns some value that can be passed from next(value).

function* forever() {
    let i = 1;
    while(true) {
        ...
        let reset = yield i++;
        if (reset === true) i = 1;
    }
}

const foreverGenerator = forever();

foreverGenerator.next();        // -> { value: 1, done: false }
foreverGenerator.next();        // -> { value: 2, done: false }
foreverGenerator.next();        // -> { value: 3, done: false }
foreverGenerator.next(true);    // -> { value: 1, done: false }
foreverGenerator.next();        // -> { value: 2, done: false }
foreverGenerator.next();        // -> { value: 3, done: false }

return method closes this generator, and allows you to also return a specific value.

foreverGererator.return('end')  // -> { value: 'end', done: true }

The throw method throws an exception inside the generator, breaking the execution if the exception is not treated.

  • If error is handled with try/catch the execution may continue with next calls.

foreverGenerator.throw('error');

Creating an Iterator with Generator

function createIterable(...args) {
    return {
        *[Symbol.iterator]() {
            let i = 0;
            while (i < array.length) {
                yield array[i++];
            }
        }
    }
}

const langs = createIterable('A', 'B', 'C');

for (let lang of langs) {
    console.log(lang);
}

Generator can also be used to syncronize async calls similar to async/await.

function sum(a, b) {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve(a + b);
        }, 1000);
    });
}

function async(gen, result) {
    const obj = gen.next(result);
    if (obj.done) return;
    obj.value.then((res) => {
        async(gen, res);
    });
}

async(function* (){
    const a = yield sum(2, 2);
    const b = yield sum(4, 4);
    const c = yield sum(a, b);
    console.log(c);
});

Async\Await

Facilitates iteration with asyncronous calls, waiting for the promise return.

Iterating over awaits

For iterating over array of promisses.

(async function() {
    try {
        const functions = [
            sum(2, 2),
            sum(4, 4),
        ];
        const results = [];
        
        for (let fn of functions) {
            const result = await fn;
            results.push(result);
        }

        const [a, b] = results;
        const c = await sum(a, b);

    } catch (e) {
        ...
    }
});

for async of

An easier way of iterating over arrays of promisses.

(async function() {
    try {
        const functions = [
            sum(2, 2),
            sum(4, 4),
        ];
        const results = [];
        
        for await (let result of functions) {
            results.push(result);
        }

        const [a, b] = results;
        const c = await sum(a, b);

    } catch (e) {
        ...
    }
});

Garbage Collector

Registering Performance

Time

console.time("Label");
...
console.timeEnd("Label");
PreviousCssNextTypescript

Last updated 7 months ago