JavaScript: Difference between revisions

From Training Material
Jump to navigation Jump to search
mNo edit summary
 
(53 intermediate revisions by the same user not shown)
Line 14: Line 14:
{{Can I use your material}}
{{Can I use your material}}


== JavaScript Intro ==
== JavaScript Intro ==


* Names, versions, etc
* Names, versions, etc
* Finished proposals
* Finished proposals


== What is this buzz all about? ==
== What is this buzz all about? ==


* All the JavaScript '''acronyms''' can be '''confusing'''
* All the JavaScript '''acronyms''' can be '''confusing'''
* Was originally named ''JavaScript'' in hopes of capitalizing on the success of ''Java''
* Was originally named ''JavaScript'' in hopes of capitalizing on the success of ''Java''
* JavaScript was submitted to ECMA International for Standardization (organization that standardizes information)
* JavaScript was submitted to ''ECMA International for Standardization'' (organization that standardizes information)
** <small>https://262.ecma-international.org</small> 
** <small>https://262.ecma-international.org</small> 
* '''ECMAScript''' is a ''standard''
* '''ECMAScript''' is a ''standard''
Line 31: Line 31:
*** <small>https://en.wikipedia.org/wiki/List_of_ECMAScript_engines</small>
*** <small>https://en.wikipedia.org/wiki/List_of_ECMAScript_engines</small>


=== Other names ===
=== Other names ===


* '''ES''' is simply short for ''ECMAScript''
* '''ES''' is simply short for ''ECMAScript''
Line 42: Line 42:
* '''ES2016''': June 2016, '''ES2017''': June 2017
* '''ES2016''': June 2016, '''ES2017''': June 2017


== Finished proposals ==
== Finished proposals ==
* All of them
* All of them
** <small>https://github.com/tc39/proposals/blob/master/finished-proposals.md</small>
** <small>https://github.com/tc39/proposals/blob/master/finished-proposals.md</small>
* ECMAScript 2016
* ECMAScript '''2016'''
* ECMAScript 2017
* ECMAScript '''2017'''
* ECMAScript 2018
* ECMAScript '''2018'''
* ECMAScript '''2019'''
* ECMAScript '''2020'''
* ECMAScript '''2021'''
* ECMAScript '''2022'''
* ECMAScript '''2023''', current


== ECMAScript 2015 ==
== ECMAScript 2015 ==
* For of
* For of
** http://es6-features.org/#IteratorForOfOperator
** http://es6-features.org/#IteratorForOfOperator
Line 60: Line 65:
** http://es6-features.org/#SpreadOperator
** http://es6-features.org/#SpreadOperator


== ECMAScript 2016 ==
== ECMAScript 2016 ==
* ''Array.prototype.includes''
* ''Array.prototype.includes''
* ''Exponentiation'' infix operator
* ''Exponentiation'' infix operator


=== Array.prototype.includes ===
=== Array.prototype.includes ===
* ''includes'' instance method on the Array  
* ''includes'' instance method on the Array  
* Helps to easily '''find''' if an '''item''' is in the '''Array''' (including NaN unlike indexOf)
* Helps to easily '''find''' if an '''item''' is in the '''Array''' (including NaN unlike indexOf)
Line 79: Line 84:
</syntaxhighlight>
</syntaxhighlight>


=== Exponentiation infix operator ===
=== Exponentiation infix operator ===
* In exponent operation the '''<big>**</big>''' was introduced instead of ''Math.pow''
* In exponent operation the '''<big>**</big>''' was introduced instead of ''Math.pow''
<syntaxhighlight lang="ts">
<syntaxhighlight lang="ts">
Line 89: Line 94:
</syntaxhighlight>
</syntaxhighlight>


== ECMAScript 2017 ==
== ECMAScript 2017 ==
* ''Object.values()''
* ''Object.values()''
* ''Object.entries()''
* ''Object.entries()''
Line 97: Line 102:
* Async/Await
* Async/Await


=== Object.values() ===
=== Object.values() ===
* New function similar to ''Object.keys()''  
* New function similar to ''Object.keys()''  
* Returns all the values of the Object’s own '''properties'''
* Returns all the values of the Object’s own '''properties'''
Line 113: Line 118:
</syntaxhighlight>
</syntaxhighlight>


=== Object.entries() ===
=== Object.entries() ===
* Also similar to ''Object.keys()''
* Also similar to ''Object.keys()''
** Returns as ''array'' both, '''keys''' and '''values'''
** Returns as ''array'' both, '''keys''' and '''values'''
Line 137: Line 142:
</syntaxhighlight>
</syntaxhighlight>


=== String padding ===
=== String padding ===
* Two new instance methods
* Two new instance methods
** ''String.prototype.padStart'' and ''String.prototype.padEnd''
** ''String.prototype.padStart'' and ''String.prototype.padEnd''
Line 157: Line 162:
</syntaxhighlight>
</syntaxhighlight>


=== Object.getOwnPropertyDescriptors ===
=== Object.getOwnPropertyDescriptors ===
* Returns all the details for all the properties of a given object
* Returns all the details for all the properties of a given object
** including methods '''get''' and '''set'''
** including methods '''get''' and '''set'''
Line 196: Line 201:
</syntaxhighlight>
</syntaxhighlight>


=== Trailing commas, function parameters ===
=== Trailing commas, function parameters ===
* Allows us to have '''trailing commas''' after the '''last''' function parameter
* Allows us to have '''trailing commas''' after the '''last''' function parameter
* Helps with tools like '''git blame''' to ensure only new developers get blamed
* Helps with tools like '''git blame''' to ensure only new developers get blamed
Line 228: Line 233:
</syntaxhighlight>
</syntaxhighlight>


=== Async/Await ===
=== Async/Await ===
* Async functions  
* Async functions  
** no callback hell  
** no callback hell  
Line 237: Line 242:
** and waits until the promise is resolved or rejected before moving further
** and waits until the promise is resolved or rejected before moving further


==== Basic example ====
==== Basic example ====
<syntaxhighlight lang="ts">
<syntaxhighlight lang="ts">
// Usual promise way
// Usual promise way
Line 278: Line 283:
}
}
</syntaxhighlight>
</syntaxhighlight>
===== Exercise =====
===== Exercise =====
Fix the example above (-:
Fix the example above (-:
<!--
<!--
Line 290: Line 295:
-->
-->


==== Async functions themselves return a Promise ====
==== Async functions themselves return a Promise ====
* If we are waiting for the result from an async function
* If we are waiting for the result from an async function
** we need to use Promise’s '''then''' syntax to capture its result
** we need to use Promise’s '''then''' syntax to capture its result
Line 310: Line 315:
</syntaxhighlight>
</syntaxhighlight>


==== Calling async/await in parallel ====
==== Calling async/await in parallel ====


* Instead of calling await twice and each time waiting for five seconds (total 10 seconds)
* Instead of calling await twice and each time waiting for five seconds (total 10 seconds)
Line 408: Line 413:
</syntaxhighlight>
</syntaxhighlight>


==== Example from Ecma docs ====
==== Example from Ecma docs ====
* https://tc39.github.io/ecmascript-asyncawait/
* https://tc39.github.io/ecmascript-asyncawait/


==== d3js examples ====
==== d3js examples ====
* ch5, index.js
* ch5, index.js
* ch2, index.js
* ch2, index.js


== ECMAScript 2018 ==
== ECMAScript 2018 ==
* Rest / spread properties
* Rest / spread properties
* Asynchronous iteration
* Asynchronous iteration
Line 491: Line 496:


=== Asynchronous Iteration ===
=== Asynchronous Iteration ===
* Asynchronous iterators and iterables
* Asynchronous '''iterators''' and '''iterables'''
** we can use the await keyword in for/of loops
** we can use the '''await''' keyword in '''for/of loops'''
* Syntax <syntaxhighlight inline lang="ts">for await () {}</syntaxhighlight>
* Syntax <syntaxhighlight inline lang="ts">for await () {}</syntaxhighlight>
<!-- [[File:AsyncIteration.png|500px]] -->
<!-- [[File:AsyncIteration.png|500px]] -->
Line 531: Line 536:


=== Additions to RegExp ===
=== Additions to RegExp ===
* Unicode Property Escapes (\p{...})
* Unicode Property Escapes ('''\p{...}''')
* Lookbehind Assertions (?<= ) and (?<! )
** <small>https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Unicode_character_class_escape</small>
* Lookbehind Assertions ('''?<=''' ) and ('''?<!''' )
** <small>https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Lookbehind_assertion</small>
* Named Capture Groups
* Named Capture Groups
* s (dotAll) Flag
** <small>https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Named_capturing_group</small>
* s ('''dotAll''') Flag
** <small>https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/dotAll</small>
<!-- TODO: examples and exercises -->
<!-- TODO: examples and exercises -->


=== Execution improvements ===
=== Execution improvements ===
* Threads - using the Web Workers API to create threads
* '''Threads''' - using the Web Workers API to create threads
** Worker threads  
** Worker threads  
*** are used to execute code in the background - main program can continue execution
*** are used to execute code in the background - main program can continue execution
*** run simultaneously with the main program - it can be time-saving
*** run simultaneously with the main program - it can be time-saving
* Shared Memory - allows threads (different parts of a program)  
* '''Shared Memory''' - allows threads (different parts of a program)  
** to access and update the same data in the same memory
** to access and update the same data in the same memory
** no passing data between threads
** no passing data between threads
** instead we can pass a SharedArrayBuffer object that points to the memory where data is saved
** instead we can pass a SharedArrayBuffer object that points to the memory where data is saved
* SharedArrayBuffer
* '''SharedArrayBuffer'''
** object which represents a fixed-length raw binary data buffer  
** object which represents a fixed-length raw binary data buffer  
** similar to the ArrayBuffer object
** similar to the ArrayBuffer object
Line 553: Line 562:


== ES2019 ==
== ES2019 ==
* String.trimStart() and String.trimEnd()
* String.'''trimStart()''' and String.'''trimEnd()'''
* Object.fromEntries
* Object.'''fromEntries'''
* Array.flat() and Array.flatMap()
* Array.'''flat()''' and Array.'''flatMap()'''
* Revised Array.Sort()
* Revised Array.'''Sort()'''
* Revised JSON.stringify()
* Revised JSON.'''stringify()'''
* Separator symbols allowed in string litterals
* '''Separator symbols''' allowed in string literals
* Revised Function.toString()
* Revised '''.toString()'''
* Optional catch binding
* Optional '''catch''' binding


=== String related ===
=== String related ===
* Previously JSON.'''stringify()''' on ''UTF-8'' code points (U+D800 to U+DFFF)
** returned '''broken''' Unicode characters like ���
* '''.toString()''' must return the source code of the function
** including comments, spaces, and syntax details
Examples
Examples
<syntaxhighlight lang="ts">
<syntaxhighlight lang="ts">
// new methods: trimStart() and trimEnd()
let text1 = "    Hi Universe!    ";
let text1 = "    Hi Universe!    ";
let text2 = text1.trimStart();
let text2 = text1.trimStart();
let text3 = text1.trimEnd();
let text3 = text1.trimEnd();
// utf8 encodings returns properly now
<div id="stringy"></div>
let text = JSON.stringify("\u26D4");
document.getElementById("stringy").innerHTML = JSON.parse(text);
// also line and paragraph separator symbols (\u2028 and \u2029)
let text = "\u2028";
// .toString() precision
const meF = (data) => `<div>${data}</div>`;
console.log( meF.toString() );
</syntaxhighlight>
</syntaxhighlight>


Line 595: Line 621:
const myArr = [
const myArr = [
   {name:"X00",price:100 },
   {name:"X00",price:100 },
   {name:"X01",price:100 },
   {name:"X08",price:120 },
  {name:"X05",price:110 },
   {name:"X04",price:110 },
   {name:"X04",price:110 },
  {name:"X05",price:110 },
  {name:"X08",price:120 },
   {name:"X09",price:120 },
   {name:"X09",price:120 },
  {name:"X01",price:100 },
];
];


myArr.sort( (p1, p2) => {
myArr.sort( (p1, p2) => {
//  if (p1.price < p2.price) return -1;
  if (p1.price < p2.price) return -1;
(p1.price < p2.price) ? -1;
  if (p1.price > p2.price) return 1;
//  if (p1.price > p2.price) return 1;
(p1.price > p2.price) ? 1;
   return 0;
   return 0;
});
});


let txt = "";
let txt = "";
const showF = (value) => txt += `${value.name} ${value.price}<br>` ;
myArr.forEach(showF);
myArr.forEach(showF);
const showF = (value) => txt += value.name + " " + value.price + "<br>";
console.log(txt);
console.log(txt);
/*
/*
Line 625: Line 648:


=== Optional catch ===
=== Optional catch ===
* Can be omitted if not needed
* Can be '''omitted''' if not needed
Example
Example
<syntaxhighlight lang="ts">
<syntaxhighlight lang="ts">
Line 642: Line 665:
}
}
</syntaxhighlight>
</syntaxhighlight>
== ES2020 ==
* '''BigInt'''
* String '''matchAll()'''
* The '''Nullish Coalescing''' Operator (??) and Assignment (??=)
* The '''Optional Chaining''' Operator (?.)
* Logical AND/OR Assignment Operators (&&=), (||=)
* Promise '''allSettled():'''
** <syntaxhighlight inline lang="ts">Promise.allSettled([prom1,prom2,prom3]).then {}</syntaxhighlight>
** Docs <small>https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled</small>
* '''Dynamic''' Import
=== BigInt ===
* '''BigInt''' variables - store big integer values
** the usual '''Number''' has only 15 digits max
* '''BigInt()''' or '''1234567890123456789n'''
Example
<syntaxhighlight lang="ts">
let x = 123456789012345678901234567890n;
let y = BigInt("123456789012345678901234567890");
console.log( typeof(x) );        // 'bigint'
</syntaxhighlight>
=== matchAll() ===
* To search for '''all occurrences''' of a string in a string
Examples
<syntaxhighlight lang="ts">
let text = "I love bugs. Bugs are very easy to love. Bugs are very popular."
const iterator = text.matchAll("Bugs");
const iterator1 = text.matchAll(/Bugs/g);      // regexps, globally
const iterator2 = text.matchAll(/Bugs/gi);    // case insensitive
console.log( Array.from(iterator) );
console.log( Array.from(iterator1) );
console.log( Array.from(iterator2) );
</syntaxhighlight>
=== Other ===
<syntaxhighlight lang="ts">
// Example of globalThis in ES11
console.log(globalThis); // Output: Window {...}
// Example of private fields
class Invoice {
    #name = "Don Joe";
    #id = 370;
    getName() {
        return this.#name;
    }
    getId() {
        return this.#age;
    }
}
let person = new Person();
console.log(person.getName()); // Output: "Don Joe"
console.log(person.getId()); // Output: 370
// Example of nullish coalescing in ES11
let value = null;
console.log(value ?? "default"); // Output: "default"
// The ?. operator returns undefined if an object is undefined or null (instead of throwing an error)
const car = {type:"Fiat", model:"500", color:"white"};
let name = car?.name;
console.log(name); // Output: "undefined"
// Logical AND, OR
let x = 100; x &&= 5;          // If the first value is true, the second value is assigned
console.log(x);
let y = undefined; y ||= 5;    // If the first value is false, the second value is assigned
console.log(y);
// Nullish Coalescing Assignment Operator
let z;
console.log( x ??= 5 );        // If the first value is undefined or null, the second value is assigned
</script>
</syntaxhighlight>
=== Dynamic imports ===
* '''import()''' - returns a Promise; it's not a function
* Lazy loading modules, on-demand, etc
* Related docs
** <small>https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import</small>
** <small>https://tc39.es/proposal-dynamic-import/</small>
Example
* Lazy Loading in Reactjs
** <small>https://react.dev/reference/react/lazy</small>
== ES2021 ==
* Promise any():
** const first = await Promise.any([prom1,prom2,prom3]);
* String replaceAll()
* Numeric Separators (_)
Some Examples
<syntaxhighlight lang="TS">
// Example of Logical Assignment Operators in ES12
let a = 0, b = 1;
a &&= b;
console.log(a); // Output: 0
a ||= b;
console.log(a); // Output: 1
a &&= b;
console.log(a); // Output: 1
// Example of Numeric Separators in ES12
let billion = 1_000_000_000; // This is equivalent to let billion = 1000000000;
console.log(billion); // Output: 1000000000
// Example of Promise.any() in ES12
let promises = [
    Promise.reject('1'),
    Promise.resolve('2'),
    Promise.reject('3')
];
Promise.any(promises)
    .then(value => console.log(value)) // Output: "2"
    .catch(error => console.log(error));
// Example of String.prototype.replaceAll() in ES12
let string = "foo foo foo";
console.log(string.replaceAll("foo", "bar")); // Output: "bar bar bar"
</syntaxhighlight>
== ES2022 ==
* Array at()
* String at()
* RegExp /d
* Object.hasOwn()
* error.cause
* await import
* Private methods and fields
* Class field declarations
Examples
<!-- TODO: use those below maybe
https://dev.to/brayanarrieta/new-javascript-features-ecmascript-2022-with-examples-4nhg
-->
== ES2023 ==
* Latest docs
** https://tc39.es/ecma262/
<!-- TODO: design examples -->


== State of JS ==
== State of JS ==
  https://stateofjs.com/
  https://stateofjs.com/


== jQuery Standards ==
== Patterns ==
http://lab.abhinayrathore.com/jquery-standards/
https://javascriptpatterns.vercel.app/patterns/performance-patterns/dynamic-import
 
== Typescript ==
* [[Typescript|Typescript basics]]


== Polish US codes ==
== Useful Additions ==
http://crd.gov.pl/xml/schematy/dziedzinowe/mf/2018/08/24/eD/DefinicjeTypy/KodyUrzedowSkarbowych_v5-0E.xsd
* Per country standards
** <small>https://www.freeformatter.com/romania-standards-code-snippets.html</small>
* Examples
** <small>http://es6-features.org/#CurrencyFormatting</small>
* Polish US codes
** <small>http://crd.gov.pl/xml/schematy/dziedzinowe/mf/2018/08/24/eD/DefinicjeTypy/KodyUrzedowSkarbowych_v5-0E.xsd</small>

Latest revision as of 09:09, 5 November 2024

THIS IS A DRAFT

This text may not be complete.


title
JavaScript
author
Lukasz Sokolowski (NobleProg)


JavaScript

JavaScript Training Materials

JavaScript Intro

  • Names, versions, etc
  • Finished proposals

What is this buzz all about?

  • All the JavaScript acronyms can be confusing
  • Was originally named JavaScript in hopes of capitalizing on the success of Java
  • JavaScript was submitted to ECMA International for Standardization (organization that standardizes information)
  • ECMAScript is a standard

Other names

  • ES is simply short for ECMAScript
  • ES followed by a number is referencing an edition of ECMAScript
  • There are 8 editions of ECMAScript published
  • ES1: June 1997, ES2: June 1998, ES3: Dec 1999, ES4: Abandoned, due to political differences
  • ES5: Dec 2009 - presently fully supported by all most popular web browsers
  • ES6 / ES2015: June 2015 - the decision was make to move to annual updates
    • From now on official name reflects the year of release (no longer ES7, ES8, etc)
  • ES2016: June 2016, ES2017: June 2017

Finished proposals

ECMAScript 2015

ECMAScript 2016

  • Array.prototype.includes
  • Exponentiation infix operator

Array.prototype.includes

  • includes instance method on the Array
  • Helps to easily find if an item is in the Array (including NaN unlike indexOf)
const setty = ['me', 'doing', 'js', NaN];

// Before, and doesn't search NaN
if ( setty.indexOf("js") >= 0 ) { console.log(true); }
setty.indexOf(NaN); // false

// Now, and searches NaN
if ( setty.includes("js") ) { console.log(true); }
setty.includes(NaN);  // true

Exponentiation infix operator

  • In exponent operation the ** was introduced instead of Math.pow
// Earlier
Math.pow(7, 2)

// Now
7**2

ECMAScript 2017

  • Object.values()
  • Object.entries()
  • String padding
  • Object.getOwnPropertyDescriptors
  • Trailing commas, function parameters
  • Async/Await

Object.values()

  • New function similar to Object.keys()
  • Returns all the values of the Object’s own properties
    • but excluding any value(s) in the prototypical chain
const bookPrices = { Thud: 20, LOTR: 50, Drupal8: 30 };

// Before
const prices = Object.keys(bookPrices).map( priceKey => bookPrices[priceKey]); 
console.log(prices); // [20, 50, 30]

// Now
const prices1 = Object.values(bookPrices);
console.log(prices1); // [20, 50, 30]

Object.entries()

  • Also similar to Object.keys()
    • Returns as array both, keys and values
    • Simplifies using objects in loops or converting objects into Maps
const bookPrices = { Thud: 20, LOTR: 50, Drupal8: 30 };
const map = new Map();

// Extracting keys and looping; map
Object.keys(bookPrices).forEach( function(priceKey) {
    console.log('Book: ' + priceKey + ' costs: ' + bookPrices[priceKey]);
    map.set(priceKey, bookPrices[priceKey]);
});
console.log(map); // Map(3) {"Thud" => 20, "LOTR" => 50, "Drupal8" => 30}

// Easier (-:
for ( let [k, v] of Object.entries(bookPrices) ) {
    console.log(`Book: ${k} costs: ${v}`);
};

const map1 = new Map(Object.entries(bookPrices));
console.log(map1);

String padding

  • Two new instance methods
    • String.prototype.padStart and String.prototype.padEnd
    • allow appending/prepending string (also empty one) to the start or the end of the original string
// printing multiple items of varying lengths and right-aligning them properly
const bookPrices = { 'Thud': '200', 'LOTR': '50', 'Drupal8': '5' };

Object.entries(bookPrices).map(([row, count]) => {
  // padEnd appends ' ~' until the row becomes 25 characters
  // padStart prepends '0' until the count becomes 4 characters
  console.log(`${row.padEnd(25, ' ~')} Costs: ${count.padStart(4, '0')}`)
});

//Prints..
// Thud ~ ~ ~ ~ ~ ~ ~ ~ ~ ~  Costs: 0200
// LOTR ~ ~ ~ ~ ~ ~ ~ ~ ~ ~  Costs: 0050
// Drupal8 ~ ~ ~ ~ ~ ~ ~ ~ ~ Costs: 0005

Object.getOwnPropertyDescriptors

  • Returns all the details for all the properties of a given object
    • including methods get and set
  • Allows shallow copying / cloning an object into another object
    • that also copies getter and setter functions (as opposed to Object.assign)
var Comic = {
 title: 'Thorgal', price: 100,
 set discount(amount) {
  this.d = amount;
 },
 get discount() {
  return this.d;
 },
};

// Print details of Comic object's 'discount' property
console.log(Object.getOwnPropertyDescriptor(Comic, 'discount'));
// Prints.. { get: [Function: get], set: [Function: set], enumerable: true, configurable: true }

// Copy Comic's properties to KindleComic using Object.assign
const KindleComic = Object.assign({}, Comic);

// Print details of KindleComic object's 'discount' property
console.log(Object.getOwnPropertyDescriptor(KindleComic, 'discount'));
// prints.. { value: undefined, writable: true, enumerable: true, configurable: true }
// getters and setters are missing..  )-:


// Copy Comic's properties to KindleComic2 using Object.defineProperties 
// and extract Comic's properties using Object.getOwnPropertyDescriptors
const KindleComic2 = Object.defineProperties({}, Object.getOwnPropertyDescriptors(Comic));

//Print details of KindleComic2 object's 'discount' property
console.log(Object.getOwnPropertyDescriptor(KindleComic2, 'discount'));
//prints.. { get: [Function: get], set: [Function: set], enumerable: true, configurable: true }
// getters and setters are present in the ElectricCar2 object for 'discount' property  (--8

Trailing commas, function parameters

  • Allows us to have trailing commas after the last function parameter
  • Helps with tools like git blame to ensure only new developers get blamed
function Comic (
  title,
  year // Devel1 does this without ','
  ){
  this.title = title;
  this.year = year;
}

function Comic (
  title,
  year,  // Devel2 has to add ','
  genre  // Devel2 can add new parameter now
  ){
  this.title = title;
  this.year = year;
  this.genre = genre;  // Devel2 adds
}

// Solution
function Comic (
  title,
  year, // Devel2 doesn't need to change here (-:
  ){
  this.title = title;
  this.year = year;
}

Async/Await

  • Async functions
    • no callback hell
    • make the entire code look simple
  • When seeing async keyword, JavaScript compiler treats the function differently
    • pauses whenever it reaches the await keyword within that function
    • assumes that the expression after await returns a promise
    • and waits until the promise is resolved or rejected before moving further

Basic example

// Usual promise way
function getInvoice(clientId) {
  getClient(clientId)
    .then(getFromTool)
    .then(invoice => {
      console.log(invoice);
    });
}

// New way
async function getInvoice2(clientId) {
  var client = await getClient(clientId);
  var invoice = await getFromTool(client);
  console.log(invoice);
}

getInvoice("Sam Sung");
getInvoice2("Sam Sung");

function getClient(clientId) {
  return new Promise( resolve => {
    setTimeout( () => {
      resolve("Sam Sung");
    }, 1000);
  });
}

function getFromTool(clientId) {
  return new Promise( (resolve, reject) => {
    setTimeout( () => {
      if ( clientId == "Sam Sung" ) {
        resolve("Inv2-03052017");
      } else {
        reject("Unknown client");
      }
    }, 1000);
  });
}
Exercise

Fix the example above (-:

Async functions themselves return a Promise

  • If we are waiting for the result from an async function
    • we need to use Promise’s then syntax to capture its result
async function glueScrabble(w1, w2) {
 w1 = await fixLetters(w1);
 w2 = await fixLetters(w2);
 return w1 + w2;
}

glueScrabble('a', 'b').then(console.log);

function fixLetters(letter) {
  return new Promise ( resolve => {

   setTimeout( () => { resolve( letter.toUpperCase() ) }, 5000); 
  });
}

Calling async/await in parallel

  • Instead of calling await twice and each time waiting for five seconds (total 10 seconds)
    • we can parallelize it since a and b are not dependent on each other using Promise.all
async function glueScrabble2(w1, w2) {
  // with Array destructuring 
  [w1, w2] = await Promise.all( [fixLetters(w1), fixLetters(w2)] );
 return w1 + w2;
}

glueScrabble2('a', 'b').then(console.log);

Error handling async/await functions

  • Use try catch within the function
  • Catch every await expression
  • Catch the entire async-await function
Use try catch within the function
// Use try catch within the function
async function glueScrabble3(w1, w2) {
  try {
    w1 = await fixLetters3(w1);
    w2 = await fixLetters3(w2);
  } catch (e) {
    return e.name;
  }
  return w1 + w2;
}

// Usage:
glueScrabble3(23, 'b').then(console.log);  // "TypeError"
glueScrabble3('a', 'b').then(console.log); // AB

function fixLetters3(letter) {
 return new Promise( (resolve, reject) => {
  setTimeout( function() {
    if ( typeof letter == "number" ) throw "Number given, should be a string"; 
    let val = letter.toUpperCase(); console.log(val);
    (!val) ? reject('TypeError') : resolve(val);
  }, 1000);
 });
}
Catch every await expression
// Catch errors on every await line
// each await expression is a Promise in itself
async function glueScrabble4(w1, w2) {
  w1 = await fixLetters4(w1).catch(e => console.log('"w1" is a Number')); // Yep (-:
  w2 = await fixLetters4(w2).catch(e => console.log('"w2" is a Number')); // Yep (-:
  if ( !w1 || !w2 ) {
    return 'Both are numbers';
  }
  return w1 + w2;
}

//Usage:
glueScrabble4(234, 'a').then(console.log); // 'TypeError' and logs:  "w1" is a Number
glueScrabble4('a', 'b').then(console.log); // AB

function fixLetters4(letter) {
 return new Promise( (resolve, reject) => {
  setTimeout( function() {
    let val = letter.toUpperCase(); // console.log(val);
    (!val) ? reject('TypeError') : resolve(val);
  }, 1000);
 });
}
Catch the entire async-await function
//Option 3 - Don't do anything but handle outside the function
//since async / await returns a promise, we can catch the whole function's error
async function doubleAndAdd(a, b) {
 a = await doubleAfter1Sec(a);
 b = await doubleAfter1Sec(b);
 return a + b;
}
//Usage:
doubleAndAdd('one', 2)
.then(console.log)
.catch(console.log); // <------- use "catch"

function doubleAfter1Sec(param) {
 return new Promise((resolve, reject) => {
  setTimeout(function() {
   let val = param * 2;
   isNaN(val) ? reject(NaN) : resolve(val);
  }, 1000);
 });
}

Example from Ecma docs

d3js examples

  • ch5, index.js
  • ch2, index.js

ECMAScript 2018

  • Rest / spread properties
  • Asynchronous iteration
  • Promise.finally()
  • Additions to RegExp

rest / spread properties

  • allows to destruct an object and collect the leftovers onto a new object

Examples

let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x; // 1
y; // 2
z; // { a: 3, b: 4 }

// or longer:
let object = {a: 1, b: 2}
let objectClone = Object.assign({}, object) // before ES2018
let objectClone = {...object} // ES2018 syntax
let otherObject = {c: 3, ...object}
console.log(otherObject) // -> {c: 3, a: 1, b: 2}

Promise.prototype.finally()

  • Allow running a callback after either resolve or reject to help clean things up
  • The finally callback is called without any value and is always executed no matter what
// Resolve case...

let started = true;

let myPromise = new Promise(function(resolve, reject) {
	resolve('all good');
})
  .then(val => {
    console.log(val); // logs 'all good'
  })
  .catch(e => {
    console.log(e); // skipped
  })
  .finally(() => {
    console.log('This function is always executed!');

    started = false; // clean up
  });

Promise.prototype.finally() Con't

  • Error handling example
// Error cas 1...
// Error thrown from Promise

let started = true;

let myPromise = new Promise(function(resolve, reject) {
	throw new Error('Error');
})
  .then(val => {
    console.log(val); // skipped
  })
  .catch(e => {
    console.log(e); // catch is called since there was an error
  })
  .finally(() => {
    // Notice that no value is passed here!
    console.log('This function is always executed!');

    started = false; // clean up
  });

Asynchronous Iteration

  • Asynchronous iterators and iterables
    • we can use the await keyword in for/of loops
  • Syntax for await () {}

Examples

const promises = [
  new Promise(resolve => resolve(1)),
  new Promise(resolve => resolve(2)),
  new Promise(resolve => resolve(3)),
];

// BEFORE:
// for-of uses regular sync iterator
// Doesn't wait for promise to resolve
async function test1(){
  for (const obj of promises){
    console.log(obj); // Logs 3 promise objects
  }
}

// AFTER:
// for-await-of uses Async iterator
// Waits for Promise to resolve for each loop
async function test2(){
  for await (const obj of promises){
    console.log(obj); // Logs 1, 2, 3
  }
}

test1(); // promise, promise, promise

test2(); // 1, 2, 3 ...prints values

Additions to RegExp

Execution improvements

  • Threads - using the Web Workers API to create threads
    • Worker threads
      • are used to execute code in the background - main program can continue execution
      • run simultaneously with the main program - it can be time-saving
  • Shared Memory - allows threads (different parts of a program)
    • to access and update the same data in the same memory
    • no passing data between threads
    • instead we can pass a SharedArrayBuffer object that points to the memory where data is saved
  • SharedArrayBuffer
    • object which represents a fixed-length raw binary data buffer
    • similar to the ArrayBuffer object

ES2019

  • String.trimStart() and String.trimEnd()
  • Object.fromEntries
  • Array.flat() and Array.flatMap()
  • Revised Array.Sort()
  • Revised JSON.stringify()
  • Separator symbols allowed in string literals
  • Revised .toString()
  • Optional catch binding

String related

  • Previously JSON.stringify() on UTF-8 code points (U+D800 to U+DFFF)
    • returned broken Unicode characters like ���
  • .toString() must return the source code of the function
    • including comments, spaces, and syntax details

Examples

// new methods: trimStart() and trimEnd()
let text1 = "     Hi Universe!     ";
let text2 = text1.trimStart();
let text3 = text1.trimEnd();

// utf8 encodings returns properly now
<div id="stringy"></div>
let text = JSON.stringify("\u26D4");
document.getElementById("stringy").innerHTML = JSON.parse(text);

// also line and paragraph separator symbols (\u2028 and \u2029)
let text = "\u2028";

// .toString() precision
const meF = (data) => `<div>${data}</div>`;
console.log( meF.toString() );

Arrays related

  • Array.prototype.flat(), Array.prototype.flatMap(), Object.fromEntries()

Examples

// Example of Array.prototype.flat() and Array.prototype.flatMap() in ES10
let array = [1, 2, [3, 4]];
console.log(array.flat()); // Output: [1, 2, 3, 4]

let numbers = [1, 2, 3, 4];
console.log(numbers.flatMap(x => [x, x*2])); // Output: [1, 2, 2, 4, 3, 6, 4, 8]

// Example of Object.fromEntries() in ES10
let entries = [['name', 'John Doe'], ['age', 30]];
console.log(Object.fromEntries(entries)); // Output: { name: "John Doe", age: 30 }

Arrays related Con't

  • More stable Array sort() method
    • previously unstable sorting algorithms (ie. QuickSort) were allowed
    • now only stable can be used
    • When sorting, elements must keep their relative position to other elements with the same value

Example

const myArr = [
  {name:"X00",price:100 },
  {name:"X08",price:120 },
  {name:"X05",price:110 },
  {name:"X04",price:110 },
  {name:"X09",price:120 },
  {name:"X01",price:100 },
];

myArr.sort( (p1, p2) => {
  if (p1.price < p2.price) return -1;
  if (p1.price > p2.price) return 1;
  return 0;
});

let txt = "";
const showF = (value) => txt += `${value.name} ${value.price}<br>` ; 
myArr.forEach(showF);
console.log(txt);
/*
when sorting on price, such result is not allowed to come:
X01 100
X00 100
X09 120
X08 120
*/

Optional catch

  • Can be omitted if not needed

Example

// Before 2019:
try {
// code
} catch (err) {
// code
}

// After 2019:
try {
// code
} catch {
// code
}

ES2020

BigInt

  • BigInt variables - store big integer values
    • the usual Number has only 15 digits max
  • BigInt() or 1234567890123456789n

Example

 let x = 123456789012345678901234567890n;
 let y = BigInt("123456789012345678901234567890");
 console.log( typeof(x) );         // 'bigint'

matchAll()

  • To search for all occurrences of a string in a string

Examples

 let text = "I love bugs. Bugs are very easy to love. Bugs are very popular."
 const iterator = text.matchAll("Bugs");
 const iterator1 = text.matchAll(/Bugs/g);      // regexps, globally
 const iterator2 = text.matchAll(/Bugs/gi);     // case insensitive

 console.log( Array.from(iterator) );
 console.log( Array.from(iterator1) );
 console.log( Array.from(iterator2) );

Other

// Example of globalThis in ES11
console.log(globalThis); // Output: Window {...}


// Example of private fields
class Invoice {
    #name = "Don Joe";
    #id = 370;

    getName() {
        return this.#name;
    }

    getId() {
        return this.#age;
    }
}

let person = new Person();
console.log(person.getName()); // Output: "Don Joe"
console.log(person.getId()); // Output: 370


// Example of nullish coalescing in ES11
let value = null;
console.log(value ?? "default"); // Output: "default"


// The ?. operator returns undefined if an object is undefined or null (instead of throwing an error)
const car = {type:"Fiat", model:"500", color:"white"};
let name = car?.name;
console.log(name); // Output: "undefined"


// Logical AND, OR
let x = 100; x &&= 5;          // If the first value is true, the second value is assigned
console.log(x);
let y = undefined; y ||= 5;    // If the first value is false, the second value is assigned
console.log(y);


// Nullish Coalescing Assignment Operator
let z;
console.log( x ??= 5 );        // If the first value is undefined or null, the second value is assigned
</script>

Dynamic imports

Example

ES2021

  • Promise any():
    • const first = await Promise.any([prom1,prom2,prom3]);
  • String replaceAll()
  • Numeric Separators (_)

Some Examples

// Example of Logical Assignment Operators in ES12
let a = 0, b = 1;
a &&= b;
console.log(a); // Output: 0
a ||= b;
console.log(a); // Output: 1
a &&= b;
console.log(a); // Output: 1

// Example of Numeric Separators in ES12
let billion = 1_000_000_000; // This is equivalent to let billion = 1000000000;
console.log(billion); // Output: 1000000000

// Example of Promise.any() in ES12
let promises = [
    Promise.reject('1'),
    Promise.resolve('2'),
    Promise.reject('3')
];
Promise.any(promises)
    .then(value => console.log(value)) // Output: "2"
    .catch(error => console.log(error));

// Example of String.prototype.replaceAll() in ES12
let string = "foo foo foo";
console.log(string.replaceAll("foo", "bar")); // Output: "bar bar bar"

ES2022

  • Array at()
  • String at()
  • RegExp /d
  • Object.hasOwn()
  • error.cause
  • await import
  • Private methods and fields
  • Class field declarations

Examples

ES2023

State of JS

https://stateofjs.com/

Patterns

https://javascriptpatterns.vercel.app/patterns/performance-patterns/dynamic-import

Typescript

Useful Additions