Since we are already a little over the second half of the year, I thought it was a good time to do a quick recap of some of the new features that **ECMAscript** brought us for 2019. All of the following features are already on Stage 4 (Finished/Approved). You can go ahead a test them in the latest versions of Chrome and Firefox.
Without question .flat
is my favorite addition to ES2019, no more using underscore or lodash for .flatten 🥳 🎉.
It takes an Array of arrays and it returns a new flattened Array.
Example
const playMe = ['Will', 'Smith', ['gettin', 'jiggy'], 'with it'].flat()
// ['Will', 'Smith', 'gettin', 'jiggy', 'with it']
Deep flattening
By default .flat
has a default deep level of 1, meaning it will only flatten the provided array going down 1 level.
It takes an optional number
as an argument to specify how many levels you want to go deeper when flattening an Array.
const someNums = [1, 2, [3, 4], [6, [7, 8, [9]]], 10]
const twoLevelsDeep = someNums.flat(2)
// [1, 2, 3, 4, 6, 7, 8, [9], 10]
const threeLevelsDeep = someNums.flat(3)
// [1, 2, 3, 4, 6, 7, 8, 9, 10]
Using .flatMap( )
The functionality of .flatMap
it’s a little bit different. First, It maps every element using the provided callback (mapping function) and afterwards, it will flat
the result array with a depth of 1.
In other words: It first maps, then flattens.
Let’s compare it with .map:
const awesomeGuys = [
{ firstName: 'Peter', lastName: 'Parker' },
{ firstName: 'Tony', lastName: 'Stark' },
{ firstName: 'Steven', lastName: 'Strange' },
{ firstName: 'Stan', lastName: 'Lee' },
]
const mapNames = awesomeGuys.map(user => Object.values(user))
// [["Peter", "Parker"], ["Tony", "Stark"], ["Stephen", "Strange"], ["Stan", "Lee"]]
const names = awesomeGuys.flatMap(user => Object.values(user))
// ["Peter", "Parker", "Tony", "Stark", "Stephen", "Strange", "Stan", "Lee"]
You may argue that you can chain .map
and .flat
to achieve the same functionally, but .flatMap
is slightly more efficient when it comes to performance and cleaner implementation.
On previous releases of ECMAscript, a couple of new methods were added to objects. Object.entries( ) was one of them, which takes an Object as an argument and returns and Array of arrays of the key-value pairs of the passed object.
Using Object.entries( )
const coolDev = { name: 'Fernando', age: 33 }
const entriesOfCoolDev = Object.entries(coolDev)
// [['name', 'fernando'], ['age', 33]];
Based on that, you can think of Object.fromEntries as the ”reverse” of Object.entries( ).
Example
const norrisArray = [
['firstName', 'Chuck'],
['lastName', 'Norris'],
['twitter', '@chucknorris'],
]
const norrisObj = Object.fromEntries(norrisArray)
// { firstName: 'Chuck', lastName: 'Norris', twitter: '@nchucknorris' }
Object.fromEntries( ) takes an Array of arrays of key-value pairs and returns an object based on that.
Passing other iterables
It can also take an iterable
as an argument. With that said it an Array
, Map
or any other object that implements the iterable protocol could be passed as an argument.
const jobPosting = new Map()
jobPosting.set('title', '10x Engineer')
jobPosting.set('languages', 'All')
jobPosting.set('socialLife', null)
jobPosting.set('salary', '$10/hr')
const myDreamJob = Object.fromEntries(jobPosting)
// { title: "10x Engineer", languages: "All", socialLife: null, salary: "$10/hr" }
Learn more about iterable protocol.
The .trimStart( )
method removes all whitespace from the beginning of a string.
On the other hand .trimEnd( )
will remove all the whitespace from the end of a string.
const leftWhitespace = ' L👀k at my left'
const righWhitespace = 'L👀k at my Right '
const noLeftWhitespace = leftNoise.trimStart()
// 'L👀k at my left'
const noRigtWhitespace = rightNoise.trimEnd()
// 'L👀k at my Right'
Something to remember is that both methods have an alias, trimStart
is the same as trimLeft
, the same with trimEnd
and trimRight
.
Now you do not have to bind an exception
variable to a catch (before it cased a SyntaxError
).
This helps avoid linting issues with unused variables when you are not actually using the exception, either because you are using your own custom one or simply because you are executing a specific task that doesn’t necessarily involve using it.
// Before you needed to specify an error
try {
...
} catch(exception) {
...
}
// New optional way
try {
...
} catch {
...
}
Just as a side note, it is still considered the best practice to handle exceptions/errors properly in a try-catch block.
Symbols got some love as well, now they accept an optional description as an argument. A very quick refresh just in case you are not familiar with them, symbols are primitives in JavaScript. The Symbol()
function guarantees to return a unique symbol value.
It’s purpose it’s to be used as an identifier for Object
properties.
const newSymbol = Symbol('ES2019 rules')
const regularSymbol = Symbol()
console.log(newSymbol.description)
// 'ES2019 rules'
console.log(regularSymbol.description)
// undefined
The only catch it’s that the description it’s only for debugging purposes.
Comparing symbols
const mySym1 = Symbol('unique')
const mySym2 = Symbol('unique')
// Let's create two symbols with the same description
console.log(Sym1 == Sym2)
// returns 'false'
Like it was mentioned before, Symbols are guaranteed to be unique. Even if we create different symbols using the same description, they will be different values always.
If you are interested you read more about Symbols here.
And that’s it! I’m always curious about how people are using these new methods to solve real-world problems. So, if you have any examples of how you are using them don’t hesitate to tag me at Twitter @fermaddev 👀.
Looking forward to the ES2020 updates 🔜!
Hope you enjoyed reading, Happy hacking! 👻