Features of modern JavaScript that you might not be aware of





Despite the fact that in the last seven years I write in JavaScript almost every working day, I must admit that I pay little attention to news about innovations from ES. The main features like async / await and proxies are one thing, but every year there is a stream of small phased changes that do not fall into my field of vision, since there is always something more important to study.



In this article, I have gathered the capabilities of modern JS, which were little talked about when they appeared. Some of them only increase usability, and some are incredibly practical and can save you writing a bunch of code.



ES2015



Binary and octal literals



JavaScript often does not have to use binary manipulation. But sometimes tasks arise that cannot be otherwise solved. For example, when you write high-performance code for weak devices, you squeeze bits into local storage, perform RGB pixel manipulations in a browser, or work with closely packed binary data formats.



All this may require a lot of work on hiding / combining binary numbers; it always seemed to me that they were in vain hidden in decimals. For such cases, the binary literal format was added to ES6: 0b



.



 const binaryZero = 0b0; const binaryOne = 0b1; const binary255 = 0b11111111; const binaryLong = 0b111101011101101;
      
      





This greatly simplifies working with binary flags:



 // Pizza toppings const olives = 0b0001; const ham = 0b0010; const pineapple = 0b0100; const artechoke = 0b1000; const pizza_ham_pineapple = pineapple | ham; const pizza_four_seasons = olives | ham | artechoke;
      
      





Same thing with octal numbers. In the JS world, this is a niche opportunity, but they are often used for networking and some file formats. You can write octal numbers using the 0o



syntax.



Number.isNaN ()



Not to be confused with window.isNaN()



, this is a new method with much more intuitive behavior.



The classic isNaN



has some interesting tricks:



 isNaN(NaN) === true isNaN(null) === false isNaN(undefined) === true isNaN({}) === true isNaN('0/0') === true isNaN('hello') === true
      
      





What does this give us? First, none of these parameters is actually NaN



. As usual, the problem is with all the “favorite” JavaScript properties: type casting. The arguments for window.isNaN



are cast to numbers using the Number



function.



The new static Number.isNaN()



method solves this problem. He once and for all returns the equality of the arguments passed to him and NaN



. This is absolutely clear:



 Number.isNaN(NaN) === true Number.isNaN(null) === false Number.isNaN(undefined) === false Number.isNaN({}) === false Number.isNaN('0/0') === false Number.isNaN('hello') === false
      
      





Signature: Number.isNaN : (value: any) => boolean







ES2016



Exponentiation operator



This happens from time to time, so it’s good to have literal syntax on hand for exponentiation:



 2**2 === 4 3**2 === 9 3**3 === 27
      
      





Strange, but I was sure that this already exists in JavaScript. Perhaps confused with Python.



Array.prototype.includes ()



It was hard to miss, but if you wrote array.indexOf(x) !== -1



in the last three years, then rejoice at the new includes



method:



 [1, 2, 3].includes(2) === true [1, 2, 3].includes(true) === false
      
      





includes



uses the Same Value Zero algorithm , which is almost identical to strict equality checking ( ===



), except that it can handle NaN



values. This algorithm also compares objects by links rather than contents:



 const object1 = {}; const object2 = {}; const array = [object1, 78, NaN]; array.includes(object1) === true array.includes(object2) === false array.includes(NaN) === true
      
      





includes



can take a second parameter, fromIndex



, which allows you to provide a shift value:



 // positions 0 1 2 3 4 const array = [1, 1, 1, 2, 2]; array.includes(1, 2) === true array.includes(1, 3) === false
      
      





Useful



Signature: Array.prototype.includes : (match: any, offset?: Int) => boolean







ES2017



Shared memory and atomic operations



These are a couple of great features that are simply invaluable if you need to do a lot of work with web workers. You can directly share memory with multiple processes and set locks to avoid race conditions.



These are two great features with fairly complex APIs, so I won’t describe them here. For details, send you to this article: https://www.sitepen.com/blog/the-return-of-sharedarraybuffers-and-atomics/ . Not all browsers support these features yet, but I hope that the situation will improve in the next couple of years.



ES2018



Gold mine of regular expressions



ES2018 has a whole bunch of new regex features:



Lookbehind matches (matching with previous characters)



In runtimes that support this, you can now write regular expressions that look for characters before you match. For example, to find all the numbers preceded by a dollar sign:



 const regex = /(?<=\$)\d+/; const text = 'This cost $400'; text.match(regex) === ['400']
      
      





It's all about the new lookbehind group, the twin lookahead groups:



 Look ahead: (?=abc) Look behind: (?<=abc) Look ahead negative: (?!abc) Look behind negative: (?<!abc)
      
      





Unfortunately, today you cannot translate the new lookbehind syntax to older browsers, so it’s quite possible that you can only use it in Node for a while.



Named Capture Groups



Regular expressions can now select subsamples and use for simple parsing. Until recently, we could refer to such fragments only by numbers, for example:



 const getNameParts = /(\w+)\s+(\w+)/g; const name = "Weyland Smithers"; const subMatches = getNameParts.exec(name); subMatches[1] === 'Weyland' subMatches[2] === 'Smithers'
      
      





And now there is the syntax for naming these subsamples (or record groups): inside the brackets at the beginning we put ?<titl>



, if we want to give the group a name:



 const getNameParts = /(?<first>\w+)\s(?<last>\w+)/g; const name = "Weyland Smithers"; const subMatches = getNameParts.exec(name); const {first, last} = subMatches.groups first === 'Weyland' last === 'Smithers'
      
      





Unfortunately, this only works on Chrome and Node now.



Dots can now mark new lines



It is only necessary to affix the /s



flag, for example, /someRegex./s



, /anotherRegex./sg



.



ES2019



Array.prototype.flat () and flatMap ()



I was very happy to see this on MDN.



Simply put, flat()



converts a multidimensional array to a one-dimensional array at a given maximum depth:



 const multiDimensional = [ [1, 2, 3], [4, 5, 6], [7,[8,9]] ]; multiDimensional.flat(2) === [1, 2, 3, 4, 5, 6, 7, 8, 9]
      
      





flatMap



is a map



followed by flat



with a depth of 1. This is useful if you need to map a function that returns an array, but you don’t need the result to be a nested data structure:



 const texts = ["Hello,", "today I", "will", "use FlatMap"]; // with a plain map const mapped = texts.map(text => text.split(' ')); mapped === ['Hello', ['today', 'I'], 'will', ['use', 'FlatMap']]; // with flatmap const flatMapped = texts.flatMap(text => text.split(' ')); flatMapped === ['Hello', 'today', 'I', 'will', 'use', 'FlatMap'];
      
      





Unlimited Catch



Now you can write try / catch expressions without reference to throwing errors:



 try { // something throws } catch { // don't have to do catch(e) }
      
      





By the way, hooks in which you do not take into account the value of e



are sometimes referred to as handling Pokémon exceptions . Because you have to catch them all!



String value trimming methods



Slightly, but nice:



 const padded = ' Hello world '; padded.trimStart() === 'Hello world '; padded.trimEnd() === ' Hello world';
      
      






All Articles