JavaScript: Difference between revisions
Jump to navigation
Jump to search
Lsokolowski1 (talk | contribs) |
Lsokolowski1 (talk | contribs) mNo edit summary |
||
(48 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 | * '''Separator symbols''' allowed in string literals | ||
* Revised | * 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:" | {name:"X08",price:120 }, | ||
{name:"X05",price:110 }, | |||
{name:"X04",price:110 }, | {name:"X04",price:110 }, | ||
{name:"X09",price:120 }, | {name:"X09",price:120 }, | ||
{name:"X01",price:100 }, | |||
]; | ]; | ||
Line 622: | 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 639: | 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/ | ||
== | == Patterns == | ||
https://javascriptpatterns.vercel.app/patterns/performance-patterns/dynamic-import | |||
== Typescript == | |||
* [[Typescript|Typescript basics]] | |||
== Polish US codes | == Useful Additions == | ||
* 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.
JavaScript
JavaScript Training Materials
Copyright Notice
Copyright © 2004-2023 by NobleProg Limited All rights reserved.
This publication is protected by copyright, and permission must be obtained from the publisher prior to any prohibited reproduction, storage in a retrieval system, or transmission in any form or by any means, electronic, mechanical, photocopying, recording, or likewise.
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
- JavaScript is the most popular implementation of that standard
- JavaScript implements ECMAScript and builds on top of it
- Other implementations: SpiderMonkey, V8, ActionScript, and more
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
- All of them
- ECMAScript 2016
- ECMAScript 2017
- ECMAScript 2018
- ECMAScript 2019
- ECMAScript 2020
- ECMAScript 2021
- ECMAScript 2022
- ECMAScript 2023, current
ECMAScript 2015
- For of
- http://es6-features.org/#IteratorForOfOperator
- d3js example, index.js, ch4
- Set
- Map
- Spread
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
- 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
- Worker threads
- 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
- 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() );
- 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 }
- 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
- String matchAll()
- The Nullish Coalescing Operator (??) and Assignment (??=)
- The Optional Chaining Operator (?.)
- Logical AND/OR Assignment Operators (&&=), (||=)
- Promise allSettled():
Promise.allSettled([prom1,prom2,prom3]).then {}
- Docs https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled
- Dynamic Import
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
- import() - returns a Promise; it's not a function
- Lazy loading modules, on-demand, etc
- Related docs
Example
- Lazy Loading in Reactjs
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
- Latest docs
State of JS
https://stateofjs.com/
Patterns
https://javascriptpatterns.vercel.app/patterns/performance-patterns/dynamic-import