JavaScript: Difference between revisions

From Training Material
Jump to navigation Jump to search
Line 820: Line 820:
* Per country standards
* Per country standards
** <small>https://www.freeformatter.com/romania-standards-code-snippets.html</small>
** <small>https://www.freeformatter.com/romania-standards-code-snippets.html</small>
* Examples
** <small>http://es6-features.org/#CurrencyFormatting</small>


== Polish US codes ==
== Polish US codes ==
  http://crd.gov.pl/xml/schematy/dziedzinowe/mf/2018/08/24/eD/DefinicjeTypy/KodyUrzedowSkarbowych_v5-0E.xsd
  http://crd.gov.pl/xml/schematy/dziedzinowe/mf/2018/08/24/eD/DefinicjeTypy/KodyUrzedowSkarbowych_v5-0E.xsd

Revision as of 23:52, 16 November 2023

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)

<syntaxhighlight lang="ts"> 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 </syntaxhighlight>

Exponentiation infix operator ⌘

  • In exponent operation the ** was introduced instead of Math.pow

<syntaxhighlight lang="ts"> // Earlier Math.pow(7, 2)

// Now 7**2 </syntaxhighlight>

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

<syntaxhighlight lang="ts"> 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] </syntaxhighlight>

Object.entries() ⌘

  • Also similar to Object.keys()
    • Returns as array both, keys and values
    • Simplifies using objects in loops or converting objects into Maps

<syntaxhighlight lang="ts"> 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); </syntaxhighlight>

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

<syntaxhighlight lang="ts"> // 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 </syntaxhighlight>

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)

<syntaxhighlight lang="ts"> 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 </syntaxhighlight>

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

<syntaxhighlight lang="ts"> 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;

} </syntaxhighlight>

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 ⌘

<syntaxhighlight lang="ts"> // 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);
 });

} </syntaxhighlight>

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

<syntaxhighlight lang="ts"> 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); 
 });

} </syntaxhighlight>

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

<syntaxhighlight lang="ts"> 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); </syntaxhighlight>

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

<syntaxhighlight lang="ts"> // 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);
});

} </syntaxhighlight>

Catch every await expression

<syntaxhighlight lang="ts"> // 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);
});

} </syntaxhighlight>

Catch the entire async-await function

<syntaxhighlight lang="ts"> //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);
});

} </syntaxhighlight>

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 <syntaxhighlight lang="ts"> 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} </syntaxhighlight>

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

<syntaxhighlight lang="ts"> // 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
 });

</syntaxhighlight>

Promise.prototype.finally() Con't

  • Error handling example

<syntaxhighlight lang="ts"> // 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
 });

</syntaxhighlight>

Asynchronous Iteration

  • Asynchronous iterators and iterables
    • we can use the await keyword in for/of loops
  • Syntax <syntaxhighlight inline lang="ts">for await () {}</syntaxhighlight>

Examples <syntaxhighlight lang="ts"> 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 </syntaxhighlight>

Additions to RegExp

  • Unicode Property Escapes (\p{...})
  • Lookbehind Assertions (?<= ) and (?<! )
  • Named Capture Groups
  • s (dotAll) Flag

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 <syntaxhighlight lang="ts"> // new methods: trimStart() and trimEnd() let text1 = " Hi Universe! "; let text2 = text1.trimStart(); let text3 = text1.trimEnd();

// utf8 encodings returns properly now

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) => `

${data}

`;

console.log( meF.toString() ); </syntaxhighlight>

Arrays related

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

Examples <syntaxhighlight lang="ts"> // 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 } </syntaxhighlight>

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 <syntaxhighlight lang="ts"> const myArr = [

 {name:"X00",price:100 },
 {name:"X01",price:100 },
 {name:"X04",price:110 },
 {name:"X05",price:110 },
 {name:"X08",price:120 },
 {name:"X09",price:120 },

];

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}
` ; 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

  • /

</syntaxhighlight>

Optional catch

  • Can be omitted if not needed

Example <syntaxhighlight lang="ts"> // Before 2019: try { // code } catch (err) { // code }

// After 2019: try { // code } catch { // code } </syntaxhighlight>

ES2020

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

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

ES2023

State of JS

https://stateofjs.com/

Patterns

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

Typescript

Useful Additions

Polish US codes

http://crd.gov.pl/xml/schematy/dziedzinowe/mf/2018/08/24/eD/DefinicjeTypy/KodyUrzedowSkarbowych_v5-0E.xsd