https://turriate.com/articles/modern-javascript-everything-you-missed-over-10-years Sandro Turriate Coder, cook, explorer Writing Projects Contact Modern Javascript: Everything you missed over the last 10 years ^ (ECMAScript 2020) JavaScript has come a long way since I knew it as the "D" in DHTML. For anyone like me, who's been reluctant to use the latest syntax that could require polyfills or a transpiler, I've written this cheatsheet to get you caught up on all the goodness that's widely supported in modern browsers. I've made this page concise, with runnable examples and links to further documentation. If you have any questions or spot any errata, please contact me. Array functions Check out all these new built-in array functions! No more need for underscore or lodash! * Array.every() * Array.filter() * Array.find() * Array.findIndex() * Array.forEach() * Array.from() * Array.includes() * Array.isArray() * Array.lastIndexOf() * Array.map() * Array.reduce() * Array.reduceRight() * Array.some() Array docs const/let These new keywords declare variables in block scope (as opposed to global or function scope). Using const implies that the value will not change as the reference is immutable. Use let if the value will change. Let documentation Nullish coalescing ?? and Optional chaining ?. operators The ?? operator checks if the value is null or undefined. No more need to use the !! check. The ?. operator checks if the value is truthy before calling the next property or function. Extremely useful when dealing with optional props. Optional chaining documentation [let a, b=1 ] [let result = a ?? b ] [print(result) ] [ ] [result = (a !== null && a !== undefined) ? a : b; ] [print(result) ] [ ] [print({x:1}?.a?.b ?? "not found") ] [ ] Async/Await The async/await keywords are here to save you from callback hell. Use await to make an asynchronous call resemble a synchronous call, i.e. running await fetchUserName() will not proceed to the next line until fetchUserName() is complete. Note, in order to use await, you have to be executing a function declared as async, i.e. async function fn(){ await fetchUserName() }. Async/Await docs. [function fetchUserName() { ] [ return new Promise(resolve => setTimeout(resolve] [} ] [ ] [async function withAsync() { ] [ print("withAsync: fetching...") ] [ await fetchUserName() ] [ print("withAsync: done") ] [} ] [await withAsync() ] [ ] [function withoutAsync() { ] [ print("withoutAsync: fetching...") ] [ fetchUserName().then(()=>print("withoutAsync don] [} ] Arrow functions ()=>{} These are functions that are bound to the current context. There are three main forms you'll see in the wild: single argument, single line, multi-line. The single argument form does not require parenthesis, and the single line form does not require a return statement; the return is implicit. 1 const fn = a => a*2 Single argument. Single line. The multi-line form requires a return statement if the function intends to returns something. Multiple arguments require parenthesis. 1 const fn = (a,b) => { 2 console.log(a,b) 3 return a*b 4 } Multiple arguments, multiple lines. Arrow function docs [function example() { ] [ this.x = 1 ] [ this.foo = function() { ] [ setTimeout(function() { ] [ print("foo lost binding. this.x = " + this.x] [ }) ] [ } ] [ this.bar = function() { ] [ setTimeout(()=> { ] [ print("bar this.x = " + this.x) ] [ }) ] [ } ] [} ] [const x = new example() ] [x.foo() ] for...of Used for looping over an iterator. Similar to for...in except you don't have to check for hasOwnProperty. You cannot use this looping syntax on an Object directly because the Object doesn't have an iterator. Instead use Object.entries({}) to retrieve an iterable. for...of docs [const x = {a: 1, b: 2} ] [for (const [key, value] of Object.entries(x)) { ] [ print(`${key}=${value}`) ] [} ] [ ] for await...of Asynchronous iteration was introduced In 2018. Much like Promise.all, it can be used to synchronize many asynchronous tasks. The example below shows 3 tasks happening asynchronously. The loop processes one result at a time, in order; in this case, the quickest tasks to complete are only evident at the end of the iteration. for await...of docs [const delay = (n) => { ] [ return new Promise((resolve) => { ] [ setTimeout(()=>{ ] [ print("resolve "+n) ] [ resolve(n) ] [ }, n) ] [ }) ] [} ] [ ] [const delays = [ ] [ delay(150), ] [ delay(50), ] [ delay(25) ] [] ] [ ] [for await (const ret of delays) { ] [ print("for loop await "+ret) ] Classes In 2015, ES6 brought classes to Javascript . Javascript classes are similar to the classes you know and love from other languages. Inheritance, class methods, getters and setters, properties, etc. Class documentation [class A { ] [ constructor(name) { ] [ this.name = name ] [ } ] [ myProp = "myProp" ] [ static foo() { ] [ print("Static method says foo") ] [ } ] [} ] [class B extends A { ] [ constructor(name, age) { ] [ super(name) ] [ this.age = age ] [ } ] [ toString() { ] [ return `${this.name} ${this.age}` ] [ } ] get/set Get and set are functions that are called like properties, i.e. person.age = 16; person.age > 18. These are very convenient when you need a dynamic or computed property. And they can be used with both classes and regular objects. get/set documentation Classes with getters and setters [class A { ] [ constructor() { ] [ this._firstName = "Jane" ] [ this._lastName = "Smith" ] [ } ] [ get fullName() { ] [ return `${this._firstName} ${this._lastName}` ] [ } ] [ set firstName(v) { ] [ this._firstName = v ] [ } ] [} ] [const a = new A() ] [print(a.fullName) ] [a.firstName = "John" ] [print(a.fullName) ] [ ] Objects with getters and setters [const x = { ] [ get now() { return new Date() } ] [} ] [print(x.now) ] [ ] function default parameters Yay! You can now specify default parameters in your function definition. Works as you would expect. Default parameter docs [function greet(msg="Hello world") { ] [ print(msg) ] [} ] [greet() ] [greet("hi") ] function named parameters With a bit of object destructuing magic, functions can now have named parameters. Named parameter docs [function greet({name = "Jane", age = 42} = {}){ ] [ print(name + " " +age) ] [} ] [greet() ] [greet({name: "John", age: 21}) ] function rest ... parameter The reset parameter allows a function to accept an arbitrary number of argumentsas an array. It's recommended to use this over arguments. Rest parameter docs [function greet(msg1, ...msgs) { ] [ print(msg1) ] [ msgs.forEach(s => print(s)) ] [} ] [greet("hi", "hello", "world") ] Object.assign and spread operator Object.assign(target, source) merges two or more objects into one. It modifies the target object in-place, so if you'd prefer a new object be created, pass an empty object literal as the first argument. Alternatively, you can use the spread operator ... to merge multiple objects together: {...obj1, ...obj2}, though bear in mind, spread will not call setters on the object, so to be the most portable, consider Object.assign. The spread operator can also be used on arrays as shown in the last code sample. Spread syntax docs [const source = {x: 1, y: 4} ] [const target = Object.assign({}, source) ] [print(JSON.stringify(target)) ] [ ] [const spread = {a: 1, b: 2, ...source} ] [print(JSON.stringify(spread)) ] [ ] [const ary1 = [1] ] [const ary = [...ary1, [2,3]] ] [print(ary) ] Destructuring Destructuring allows you to extract values from objects and arrays through patterns. It is a complex topic with many applications...far too many for me to enumerate, but I've shown some of the most common uses I can think of. Destructuring docs and MDN docs [function f() { ] [ return [1, 2]; ] [} ] [let [a, b] = f() ] [print("a="+a + " b=" + b) ] [ ] [const obj = {state: {id: 1, is_verified: false}} ] [const {id, is_verified: verified} = obj.state ] [print("id = " + id) ] [print("verified = " + verified) ] [ ] [for (const [key, value] of Object.entries({a: 1, b] [ print(key + " is " + value); ] [} ] [ ] Shorthand functions aka Methods Functions declared on objects can use a new shorthand style that omits the function keyword. The two functions (fn1, fn2) are equivalent in the sample below. Method guide [const x = { ] [ type: "x", ] [ shorthand() { ] [ print("shorthand "+this.type) ] [ }, ] [ long: function() { ] [ print("long "+this.type) ] [ } ] [} ] [x.shorthand() ] [x.long() ] [ ] Promise.all I've mostly skipped over promises because async/await is preferred, but sometimes you need to synchronize multiple asynchronous calls, and Promise.all is the easiest way to do it. Promise.all documentation [const delay = (n) => { ] [ return new Promise((resolve) => { ] [ setTimeout(()=> resolve(n), n) ] [ }) ] [} ] [async function main() { ] [ const delays = [100, 200, 300].map(n => delay(n)] [ print("waiting...") ] [ const res = await Promise.all(delays) ] [ print("done. result is " + res) ] [} ] [main() ] Template literals Also known as template strings, this new syntax provides easy string interpolation and multi-line strings. Template literal docs [let x = `multi ] [ line ] [string` ] [print(x) ] [ ] [x = `1+1=${1+1}` ] [print(x) ] Proxy A Proxy allows you to intercept get/set calls on another object. This could be useful for watching a property for changes, then updating the DOM, or making innovative APIs like the www proxy below. www proxy program Proxy docs [let _nums = [1,2,3] ] [let nums = new Proxy(_nums, { ] [ set(target, key, value) { ] [ target[key] = value ] [ print("set called with " + key + "=" + value) ] [ print("update DOM") ] [ return true ] [ } ] [}) ] [nums.push(4) ] [print("nums: " + nums) ] [print("_nums: " + _nums) ] Module import/export Modules allow you to namespace your code and break down functionality into smaller files. In the example below, we have a module named greet.js that gets included in index.html. Note, module loading is always deferred, so it won't block the HTML from rendering. There are many ways to import/export functionality from js files, read more in the export docs. Import docs 1 function greet(msg) { 2 console.log("greet:", msg) 3 } 4 export default greet A file named "greet.js" in the "/js" directory. 1 index.html Read More Okay, so I didn't cover everything that's changed over the last decade, just the items I find most useful. Check out these other topics. References * Map * Set * Generator * Strict mode * Array methods * Object static methods * Reflect * URL Guides * Javascript.info * Exploring ES6 * Javascript History * Non-blocking JS loading with async/defer Apr 15, 2021 [small] Hellooooo! I'm Sandro Thank you for visiting my online presence. I'm a software developer living in San Francisco, CA who's passionate about writing concise, readable, and performant code. I also love to cook, and explore nature regionally and beyond. (c)2009-2021