JavaScript: Difference between revisions
Lsokolowski1 (talk | contribs) |
Lsokolowski1 (talk | contribs) m →ES2019 |
||
Line 553: | Line 553: | ||
== 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 === |
Revision as of 21:28, 15 November 2023
THIS IS A DRAFT
This text may not be complete.
JavaScript
JavaScript Training Materials
Copyright Notice
Copyright © 2004-2025 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 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)
<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
- 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 ���
Examples <syntaxhighlight lang="ts"> // 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); </syntaxhighlight>
- 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>
- 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>
State of JS
https://stateofjs.com/
jQuery Standards
http://lab.abhinayrathore.com/jquery-standards/
Polish US codes
http://crd.gov.pl/xml/schematy/dziedzinowe/mf/2018/08/24/eD/DefinicjeTypy/KodyUrzedowSkarbowych_v5-0E.xsd