- type: FrontEnd
- Title: ES5 to ESNext — Here’s every feature added to JavaScript since 2015
- Link: medium.freecodecamp.org/es5-to-esne…
- author: Flavio Copes
ES5 to ESNext — All the new features added to JavaScript since 2015
The purpose of this article is to help front-end developers connect with JavaScript before and after ES6, and to quickly understand the latest developments in the JavaScript language.
JavaScript is currently in a privileged position because it is the only language that runs in the browser and is highly integrated and optimized.
JavaScript has a great future, and keeping up with it won’t be any harder than it is now. My goal is to give you a quick and comprehensive overview of what’s new and available in the language.
Click here for PDF/ePub/Mobi version
directory
ECMAScript profile
ES2015
- Let and const
- Arrow function
- class
- The default parameters
- Template string
- Deconstruction assignment
- Enhanced object literals
- For – loops
- Promises
- The module
- A String of new methods
- New method Object
- Expansion operator
- Set
- Map
- Generators
ES2016
- Array.prototype.includes()
- Exponentiation operator
ES2017
- String padding
- Object.values()
- Object.entries()
- Object.getOwnPropertyDescriptors()
- The tail comma
- Shared memory and atomic operations
ES2018
- Rest/Spread Properties
- Asynchronous iteration
- Promise.prototype.finally()
- Regular expression improvement
ESNext
- Array.prototype.{flat,flatMap}
- Try /catch Optional parameter binding
- Object.fromEntries()
- String.prototype.{trimStart,trimEnd}
- Symbol.prototype.description
- JSON improvements
- Well-formed JSON.stringify()
- Function.prototype.toString()
ECMAScript profile
Whenever I read javascript-related articles, I often come across terms like this: ES3, ES5, ES6, ES7, ES8, ES2015, ES2016, ES2017, ECMAScript 2017, ECMAScript 2016, ECMAScript 2015, etc.
They all refer to a standard called ECMAScript.
JavaScript is implemented based on this standard, and ECMAScript is often abbreviated to ES.
In addition to JavaScript, other ecMAScript-based implementation languages include:
- ActionScript(Flash scripting language), which is losing popularity as Adobe discontinues support for Flash at the end of 2020.
- JScriptAt the height of the First Browser War, JavaScript was only supported by Netscape and Microsoft had to build their own scripting language for Internet Explorer.
But the most widely circulated and influential language implementation based on the ES standard is undoubtedly JavaScript
Why do you use such a strange name? Ecma International is the Swiss standards Association responsible for setting International standards.
After JavaScript was created, it was submitted to the European Computer Manufacturers Association for standardization by Netscape and Sun Microsystems and adopted as ECMA-262 under the name ECMAScript.
This press release by Netscape and Sun Microsystems (the maker of Java) might help figure out the name choice, which might include legal and branding issues by Microsoft which was in the committee, according to Wikipedia.
After IE9, references to the JScript name were removed from Microsoft’s browsers, which were instead referred to as JavaScript.
As a result, aS of 201x, JavaScript is the most popular language implemented based on the ECMAScript specification.
The current version of ECMAScript.
The latest version of ECMAScript is ES2018.
Released in June 2018.
What is TC39?
Technical Committee 39 (TC39) is a Committee that promotes the development of JavaScript.
TC39’s membership includes major browser vendors and companies whose businesses are closely related to browsers, including Mozilla, Google, Facebook, Apple, Microsoft, Intel, PayPal, SalesForce, and others.
Each standard version proposal must go through four different stages, which are explained in detail here.
ES Versions
What puzzles me is that the ES version is sometimes named after the iteration version number, but sometimes after the year. And the uncertainty of the naming makes it easier for people to confuse the two concepts of JS/ES 😄.
Prior to ES2015, naming conventions for various versions of ECMAScript were generally consistent with version updates that followed the standard. As a result, the official version of the 2009 ECMAScript specification update is ES5.
Why does this happen? During the process that led to ES2015, the name was changed from ES6 to ES2015, but since this was done late, people still referenced it as ES6, And the community has not left the edition naming behind — the world is still calling ES releases by edition number. Why is all this happening? During the creation of ES2015, the name was changed from ES6 to ES2015, but since it was finalized too late, people still called it ES6, and the community didn’t leave the version number behind completely — the world still uses ES to define the version number.
The following figure clearly shows the relationship between version numbers and years:
Next, let’s take a closer look at the JavaScript features that have been added since ES5.
Let and const
Before ES2015, var was the only statement that could be used to declare variables.
var a = 0
Copy the code
If you omit var, you will assign the value (0) to an undeclared variable. There is some difference between declared and undeclared variables.
In modern browsers with strict mode enabled, assigning an undeclared variable raises a ReferenceError. In older browsers (or with strict mode disabled), an undeclared variable will implicitly become a property of a global object when performing an assignment.
When you declare a variable but do not initialize it, its value is undefined until you assign it.
var a //typeof a === 'undefined'
Copy the code
You can redeclare a variable multiple times and override it:
var a = 1
var a = 2
Copy the code
You can also declare multiple variables at once in a single declaration:
var a = 1, b = 2
Copy the code
A scope is the part of your code that a variable can access.
Variables declared with var outside of functions are assigned to global objects, which can be accessed in the global scope. Variables declared inside a function can only be accessed in the function’s local scope, similar to function parameters.
If the name of a local variable defined in a function is the same as the name of a global variable, then the local variable has higher priority and the global variable with the same name cannot be accessed in the function.
Note that var has no block-level scope (the identifier is a pair of curly braces), but var has a function scope, so declaring a variable in a newly created block-level scope or function scope overwrites a global variable with the same name, because var does not create a new scope in either case.
Inside a function, any variables defined in it are visible in all function code, because JavaScript actually moves all variables to the top level (something called hanging) before executing the code. Variables defined inside a function are visible (accessible) throughout the function scope, even if they are declared at the end of the function body, but can still be referenced at the beginning of the function body because of JavaScript’s variable promotion mechanism. To avoid confusion, declare variables at the beginning of a function to develop good coding practices.
Using let
Let, a new feature introduced in ES2015, is essentially a VAR with block-level scope. It can be accessed by the current scope (function and block-level scope) as well as by its child scope.
Modern JavaScript developers may prefer let over VAR.
If let seems like an abstract term, it makes sense when you read let color = ‘red’ because the use of let defines color as red.
Using let to declare variables outside of any function, as opposed to var, does not create global variables.
Using const
Variables declared using var or let variables can be reassigned. Once a variable declared with const is initialized, its value can never be changed; that is, it cannot be reassigned.
const a = 'test'
Copy the code
We can’t assign to a anymore. However, if a is an object that has properties or methods, then we can change its properties or methods.
Const does not imply immutability, only that the reference address of a variable declared with const is not changed.
Like let, const also has block-level scope.
Modern JavaScript developers should use const whenever possible when encountering variable declarations that do not perform secondary assignment.
Arrow function
The introduction of arrow functions has greatly changed the writing style and some of the working mechanisms of code.
In my opinion, arrow functions are very popular with developers, and the function keyword is now rarely seen in the newer code base, although it is not obsolete.
The arrow function looks much cleaner because it allows you to write functions in shorter syntax:
const myFunction = function() {
/ /...
}
Copy the code
to
const myFunction = (a)= > {
/ /...
}
Copy the code
If the function body contains only one statement, you can even omit the braces and write the statement directly:
const myFunction = (a)= > doSomething()
Copy the code
Arguments are passed in parentheses:
const myFunction = (param1, param2) = > doSomething(param1, param2)
Copy the code
If the function has only one argument, the parentheses can be omitted:
const myFunction = param= > doSomething(param)
Copy the code
This short syntax makes it easier to use shorter functions
Implicit return
Arrow functions support implicit return: you can return a value without using the return keyword.
An implicit return only works if the function body contains only one statement:
const myFunction = (a)= > 'test'
myFunction() //'test'
Copy the code
One case to be aware of is when an object is returned, enclose braces in brackets to avoid ambiguity and parse it into braces in the body of the function.
const myFunction = (a)= > ({ value: 'test' })
myFunction() //{value: 'test'}
Copy the code
In the arrow functionthis
This can be a difficult concept to master, as it varies from context to context and can behave differently in different JavaScript modes (strict mode or not).
Understanding the concept of this is important for using arrow functions because they behave very differently than regular functions.
When the method of the object is a regular function, the this in the method refers to the object, so we can do this:
const car = {
model: 'Fiesta'.manufacturer: 'Ford'.fullName: function() {
return `The ${this.manufacturer} The ${this.model}`}}Copy the code
Executing car.fullname () returns “Ford Fiesta”.
If the above method uses an arrow function, since the scope of this in the arrow inherits from the execution context, the arrow function itself is not bound to this, so the value of this will be looked up in the call stack, so the code car.fullname () does not return the same result as the normal function. Will actually return the string “undefined “:
const car = {
model: 'Fiesta'.manufacturer: 'Ford'.fullName: (a)= > {
return `The ${this.manufacturer} The ${this.model}`}}Copy the code
Therefore, arrow functions are not suitable as object methods.
Similarly, arrow functions are not suitable for use as creation constructors because TypeError is thrown when the object is instantiated.
So use regular functions when you don’t need dynamic context.
Of course, there are problems with using arrow functions on event listeners. Because DOM event listeners automatically bind this to the target element, if the event handler’s logic depends on this, the normal function is needed:
const link = document.querySelector('#link')
link.addEventListener('click', () = > {// this === window
})
const link = document.querySelector('#link')
link.addEventListener('click'.function() {
// this === link
})
Copy the code
Classes class
JavaScript implements inheritance in a rare way: archetypal inheritance. While archetypal inheritance is great in my opinion, it differs from the inheritance implementation mechanism of most other popular programming languages, which is class-based.
The ECMAScript committee decided to implement class syntactic sugar on top of prototype inheritance to make JavaScript code easier to understand for developers of other languages that implement class-based inheritance.
Note: Class doesn’t change JavaScript at the bottom, and you can still access object prototypes directly.
The class definition
Here is an example of a class:
class Person {
constructor(name) {
this.name = name
}
hello() {
return 'Hello, I am ' + this.name + '. '}}Copy the code
Class has an identifier, and we can use new ClassIdentifier() to create an object instance.
When the object is initialized, the constructor method is called and arguments are passed to it.
Class declaration statements can also add some of the stereotype methods required by the class. In this case, Hello is a prototype method of the Person class that can be called on an object instance of the class:
const flavio = new Person('Flavio')
flavio.hello()
Copy the code
The Class inheritance
A subclass can extend another class, and objects instantiated by subclasses can extend all methods of both classes.
If a method in a subclass has the same name as a method in its parent class, then a method in a subclass with the same name takes precedence:
class Programmer extends Person {
hello() {
return super.hello() + ' I am a programmer.'}}const flavio = new Programmer('Flavio')
flavio.hello()
Copy the code
(The above code prints: “Hello, I am Flavio. I am a Programmer.”)
Class does not display class variable declarations, but you must initialize class member variables in the initialization constructor.
In subclasses, you can refer to the parent class by calling super().
A static method
In a class, methods are usually mounted directly to the instance object and invoked directly on the instance object.
Static methods are called directly from the class name, not from the object instance:
class Person {
static genericHello() {
return 'Hello'
}
}
Person.genericHello() //Hello
Copy the code
Private methods
JavaScript has no truly protected private methods built in.
The community has solutions, but I’m not going to explain them here.
Getters and setters
You can create getters and setters by prefixing methods get or set. Getters and setters will execute methods in get or set when you go to get or modify a particular value.
class Person {
constructor(name) {
this._name = name
}
set name(value) {
this._name = value
}
get name() {
return this._name
}
}
Copy the code
If you only have a getter, the property cannot be set, and any attempts to set it are ignored:
class Person {
constructor(name) {
this._name = name
}
get name() {
return this._name
}
}
Copy the code
If you have only one setter, you can change the value, but you can’t access it externally:
class Person {
constructor(name) {
this._name = name
}
set name(value) {
this._name = value
}
}
Copy the code
The default parameters
The function doSomething takes a param1 argument.
const doSomething = (param1) = >{}Copy the code
We can set a default value for param1, which is automatically set to default if no parameter is passed when the function is called.
const doSomething = (param1 = 'test') = >{}Copy the code
Of course, this mechanism also works for multiple parameters:
const doSomething = (param1 = 'test', param2 = 'test2') = >{}Copy the code
What if your function is an object with a particular property?
Once upon a time, if we had to take the value of a particular property of an object, you would have to add some code to the function for compatibility processing (the object is not formatted correctly) :
const colorize = (options) = > {
if(! options) { options = {} }const color = ('color' in options) ? options.color : 'yellow'. }Copy the code
By deconstructing, you can provide default values for specific attributes, which greatly simplifies code:
const colorize = ({ color = 'yellow' }) = >{... }Copy the code
If no object is passed when we call colorize, we can also get a default object as an argument to use:
const spin = ({ color = 'yellow' } = {}) = >{... }Copy the code
Template string
Template strings are different from previous versions of ES5, and you can use strings in novel ways.
This syntax seems very simple, just replace single or double quotes with a single backquote:
const a_string = `something`
Copy the code
This usage is unique in that it provides many functions that ordinary strings do not, such as:
- It provides a good syntax for defining multi-line strings
- It provides an easy way to insert variables and expressions into a string
- It allows you to create DSLS with template tags (DSLS mean domain-specific languages, for example, as styled components define your component’s CSS in React)
Let’s dive into the details of each feature.
Multiline string
Prior to the ES6 standard, creating a string spanning two lines could only use the ” character at the end of the line:
const string =
'first part \
second part'
Copy the code
This allows you to create strings that span two lines but still render as one line:
first part second part
Copy the code
To render multiple lines, add ‘\n’ at the end of the line, as in:
const string =
'first line\n \
second line'
Copy the code
or
const string = 'first line\n' + 'second line'
Copy the code
Template strings make it easier to define multi-line strings.
A template string starts with a backquote, you just press Enter to create a new line, no special symbols need to be inserted, and the final rendering looks like this:
const string = `Hey this string is awesome! `
Copy the code
Note that Spaces have special meaning here if you do:
const string = `First Second`
Copy the code
It creates a string like this:
First
Second
Copy the code
There is a simple way to fix this, just make the first line empty and then call a trim() method after adding the translation on the right to remove all Spaces before the first character:
const string = `
First
Second`.trim()
Copy the code
The interpolation
Template strings provide a convenient way to insert variables and expressions
You just need to use ${… } syntax
const var = 'test'
const string = `something The ${var}` //something test
Copy the code
You can add anything to ${}, even expressions:
const string = `something The ${1 + 2 + 3}`
const string2 = `something ${foo() ? 'x' : 'y'}`
Copy the code
Template tags
Tag templates may not sound like a very useful feature, but they are actually used by many popular libraries, such as Styled Components, Apollo, and the GraphQL client/server library, so it is crucial to understand how it works.
Used in the Styled Components template tag to define the CSS string
const Button = styled.button` the font - size: 1.5 em. background-color: black; color: white; `
Copy the code
In Apollo, the template tag is used to define the GraphQL query schema:
const query = gql` query { ... } `
Copy the code
Styled. Button and the GQL template tag in the two examples above are functions:
function gql(literals, ... expressions) {}
Copy the code
This function returns a string, which can be of any type.
Literals are sequences of template literals that contain expression interpolation. Expressions contain all interpolation.
Here’s an example:
const string = `something The ${1 + 2 + 3}`
Copy the code
The literal in this example is a sequence of two parts. Part 1 is something, which is the string before the first interpolation position (${}), and part 2 is an empty string from the first interpolation position to the end of the string.
The expression in this example is a sequence of only one part, which is 6.
To take a more complicated example:
const string = `something
another The ${'x'}
new line The ${1 + 2 + 3}
test`
Copy the code
The first part of the sequence of literals in this example is:
;`something
another `
Copy the code
Part 2 is:
;`
new line `
Copy the code
Part 3 is:
;`
test`
Copy the code
The expression in this example contains two parts: x and 6.
The function that takes these values can do whatever it wants with them, and that’s the power of this feature.
For example, the simplest is string interpolation, concatenating literals with expressions:
const interpolated = interpolate`I paid The ${10}Euro `
Copy the code
The process of interpolation is:
function interpolate(literals, ... expressions) {
let string = ` `
for (const [i, val] of expressions) {
string += literals[i] + val
}
string += literals[literals.length - 1]
return string
}
Copy the code
Deconstruction assignment
Given an object, you can extract some of its values and assign them to the named variable:
const person = {
firstName: 'Tom'.lastName: 'Cruise'.actor: true.age: 54.//made up
}
const {firstName: name, age} = person
Copy the code
Name and age contain corresponding values.
The same syntax applies to arrays:
const a = [1.2.3.4.5]
const [first, second] = a
Copy the code
This statement creates three new variables that take the values of the 0, 1, and 4 indices of array A:
const [first, second, , , fifth] = a
Copy the code
More powerful object literals
ES2015 gives object literals more power.
Simplified syntax for including variables
Originally written:
const something = 'y'
const x = {
something: something
}
Copy the code
New writing:
const something = 'y'
const x = {
something
}
Copy the code
The prototype
Stereotypes can be specified as follows:
const anObject = { y: 'y' }
const x = {
__proto__: anObject
}
Copy the code
super()
const anObject = { y: 'y'.test: (a)= > 'zoo' }
const x = {
__proto__: anObject,
test() {
return super.test() + 'x'
}
}
x.test() //zoox
Copy the code
Dynamic properties
const x = {
['a' + '_' + 'b'] :'z'
}
x.a_b //z
Copy the code
For – loops
ES5 2009 introduced the forEach() loop, which is useful, but unlike the for loop, can’t be broken.
ES2015 introduces the **for-of** loop, which is a break function on the basis of forEach:
//iterate over the value
for (const v of ['a'.'b'.'c']) {
console.log(v);
}
//get the index as well, using `entries()`
for (const [i, v] of ['a'.'b'.'c'].entries()) {
console.log(index) //index
console.log(value) //value
}
Copy the code
Notice the use of const. The loop creates a new scope with each iteration, so we can use const instead of let.
It goes with the for… The difference between in and out is:
for... of
Iterate over property valuesfor... in
Iterate over the property name
Promises
The general definition of a promise is that it is a proxy through which you can eventually get a value.
Promises are a way to handle asynchronous code and write fewer callbacks.
Asynchronous functions are built on top of the Promise API, so understanding promises is a basic requirement.
A brief introduction to the principle of Promise
When a promise is called, it is first in the pending state. During the processing of a promise, the called function (caller) can continue to execute until the promise gives feedback.
At this point, the called function waits for the Promise result to be either resolved or Rejected. But because JavaScript is asynchronous, the function continues to execute during promise processing.
Why does JS API use Promises?
In addition to your code and third-party library code, Promise is used in modern Web apis, such as:
- Battery API
- Fetch API
- Service Workers
In modern JavaScript, it’s impossible not to use promises, so let’s take a closer look at promises.
Create a Promise
The Promise API exposes a Promise constructor that can be initialized with new Promise() :
let done = true
const isItDoneYet = new Promise((resolve, reject) = > {
if (done) {
const workDone = 'Here is the thing I built'
resolve(workDone)
} else {
const why = 'Still working on something else'
reject(why)
}
})
Copy the code
The Promise checks the done global variable and returns a Resolved Promise if it is true, and a Rejected Promise if it is not.
Resolve and Reject give us a return value, which can be either a string or an object.
Use a Promise
Here’s how to create a promise. Here’s how to consume it.
const isItDoneYet = new Promise(a)/ /...
const checkIfItsDone = (a)= > {
isItDoneYet
.then(ok= > {
console.log(ok)
})
.catch(err= > {
console.error(err)
})
}
Copy the code
The checkIfItsDone() method executes the isItDoneYet() promise and waits for it to resolve using the then callback and, if there is an error, a catch callback.
Chain promise
A promise can return another promise to create a promise chain.
A good example of this is the Fetch API, which is a superlayer API based on the XMLHttpRequest API that you can use to Fetch resources and execute a series of chained promises when the resources are fetched.
The Fetch API is a promise-based mechanism, and calling Fetch () is equivalent to declaring our own promise using New Promise().
The example of chained promises
const status = response= > {
if (response.status >= 200 && response.status < 300) {
return Promise.resolve(response)
}
return Promise.reject(new Error(response.statusText))
}
const json = response= > response.json()
fetch('/todos.json')
.then(status)
.then(json)
.then(data= > {
console.log('Request succeeded with JSON response', data)
})
.catch(error= > {
console.log('Request failed', error)
})
Copy the code
In this example, we call fetch(), get a list of TODO items from the todos.json file in the root directory, and create a chained promise.
Running the fetch() method returns a response containing many attributes, from which we refer to the following:
status
, a value representing the HTTP status codestatusText
, a status message that is returned when the request is successfulOK
Response also has a JSON () method, which returns a promise that returns the result of converting the content to JSON.
So the invocation of these promises is: The first promise executes a status() method that we define, checks response Status, determines if it is a successful response (status between 200 and 299), and rejects the promise if it is not.
The reject operation causes the entire chained promise to skip all subsequent promises and go directly to the catch() statement, printing Request failed and error messages.
If the promise is successful, it calls the JSON () function we defined. Because the response object returned after the previous promise succeeded, we can take it and pass it in as an argument to the second promise.
In this example, we return JSON serialized data, so the third promise accepts the JSON directly:
.then((data) = > {
console.log('Request succeeded with JSON response', data)
})
Copy the code
Then we print it to console.
Handling errors
In the example in the previous section, we had a catch followed by a chained promise.
When either of the promise chains is wrong or reject, it jumps directly to the nearest catch() statement following the promise chain.
new Promise((resolve, reject) = > {
throw new Error('Error')
}).catch(err= > {
console.error(err)
})
// or
new Promise((resolve, reject) = > {
reject('Error')
}).catch(err= > {
console.error(err)
})
Copy the code
Cascading error
If you throw an error inside a catch(), you can follow it up with a second catch() to handle the error, and so on.
new Promise((resolve, reject) = > {
throw new Error('Error')
})
.catch(err= > {
throw new Error('Error')
})
.catch(err= > {
console.error(err)
})
Copy the code
Organize multiple Promises
Promise.all()
If you want to fulfill different promises at the same time, declare a series of promises with promise.all (), and then perform some actions when they are all resolved.
Example:
const f1 = fetch('/something.json')
const f2 = fetch('/something2.json')
Promise.all([f1, f2])
.then(res= > {
console.log('Array of results', res)
})
.catch(err= > {
console.error(err)
})
Copy the code
Using ES2015’s deconstructing assignment syntax, you can write:
Promise.all([f1, f2]).then(([res1, res2]) = > {
console.log('Results', res1, res2)
})
Copy the code
This is not limited to using fetch, of course; this applies to any promise.
Promise.race()
Promise.race() runs all promises passed in, but as soon as one of the resolve promises is resolved, the callback is run, and only once. The argument to the callback is the result of the first resolve Promise.
Example:
const promiseOne = new Promise((resolve, reject) = > {
setTimeout(resolve, 500.'one')})const promiseTwo = new Promise((resolve, reject) = > {
setTimeout(resolve, 100.'two')})Promise.race([promiseOne, promiseTwo]).then(result= > {
console.log(result) // 'two'
})
Copy the code
The module
ES Module is the ECMAScript standard for handling modules.
While Node.js has been using the CommonJS standard for years, browsers have never had a modular system, because decisions about modular systems need to be implemented first by browser vendors after ECMAScript standardization.
This standardization has been done in ES2015, and browsers are starting to implement it, and everyone is trying to be consistent and work the same way. ES Module is now available in Chrome Safari Edge and Firefox (starting with version 60).
Modules are cool because they allow you to encapsulate various functions and expose those functions as libraries to other JavaScript files.
ES module syntax
Introduce the syntax of the module:
import package from 'module-name'
Copy the code
CommonJS is used like this:
const package = require('module-name')
Copy the code
A module is a JavaScript file that exports one or more values (objects, functions, or variables) using the export keyword. For example, the following module provides a function to uppercase a string:
uppercase.js
export default str => str.toUpperCase()
Copy the code
In this case, the module defines a single default export, so it can be an anonymous function. Otherwise, a name is required to distinguish it from other exports.
Now, any other JavaScript module can import upperCase.js via import.
An HTML page can add a module by using the
<script type="module" src="index.js"></script>
Copy the code
Note: The module import behaves just like the *defer* script load. Read read load JavaScript with defer and async
It is important to note that any scripts loaded with type=”module” will be loaded in strict mode.
In this case, the uppercase.js module defines a default export, so when we import it we can give it any name we like:
import toUpperCase from './uppercase.js'
Copy the code
And we can use it like this:
toUpperCase('test') //'TEST'
Copy the code
You can also import modules via an absolute path. Here is an example of a reference to a module defined under another field:
import toUpperCase from 'https://flavio-es-modules-example.glitch.me/uppercase.js'
Copy the code
Here are also some valid import syntax:
import { toUpperCase } from '/uppercase.js'
import { toUpperCase } from '.. /uppercase.js'
Copy the code
The following are incorrect uses:
import { toUpperCase } from 'uppercase.js'
import { toUpperCase } from 'utils/uppercase.js'
Copy the code
Because we’re not using absolute addresses or relative addresses.
Additional import/export syntax
We see the above example:
export default str => str.toUpperCase()
Copy the code
A default export is generated here. However, you can export multiple functions in a single file using the following syntax:
const a = 1
const b = 2
const c = 3
export { a, b, c }
Copy the code
Another module can import all using the following method:
import * from 'module'
Copy the code
You can also import only parts of the assignment by deconstructing it:
import { a } from 'module'
import { a, b } from 'module'
Copy the code
For convenience, you can also rename anything that is imported using as:
import { a, b as two } from 'module'
Copy the code
You can import the default exit in the module as well as any non-default exit by name:
import React, { Component } from 'react'
Copy the code
This is an article about the ES module, which can be seen at glitch.com/edit/#! / fla…
CORS(Cross-domain Resource Sharing)
The remote acquisition of modules follows the CORS mechanism. This means that when you reference remote modules, you must use valid CORS headers to Allow cross-domain Access (e.g. Access-control-allow-origin: *).
What should I do about browsers that don’t support modules?
Use this with type=”module” and nomodule:
<script type="module" src="module.js"></script>
<script nomodule src="fallback.js"></script>
Copy the code
Packing module
The ES module is a feature of modern browsers. These features are part of the ES6 specification and are a long way from being fully implemented in the browser.
We can use them now! But we also need to know that there are some modules that can have a performance impact on the performance of our pages. Because the browser has to execute them at runtime.
Webpack will probably still be heavily used, even though the ES module can be executed in a browser. But this feature built into the language is a great unification between clients and NodeJS when using modules.
New string methods
Any string has some instance methods:
repeat()
codePointAt()
repeat()
Repeat the string as many times as specified:
'Ho'.repeat(3) //'HoHoHo'
Copy the code
Returns an empty string if no argument is provided and 0 is used as an argument. If you give a negative parameter, you get a RangeError.
codePointAt()
This method can be used to handle characters that require two UTF-16 unit representations.
To use charCodeAt, you need to get two utF-16 codes separately and combine them. But with codePointAt() you can get the entire character directly.
Here is an example, the Chinese “𠮷” is a combination of two UTF-16 encodings:
"𠮷".charCodeAt(0).toString(16) //d842
"𠮷".charCodeAt(1).toString(16) //dfb7
Copy the code
If you combine two Unicode characters:
"\ud842\udfb7" / / "𠮷"
Copy the code
You can also get the same result with codePointAt() :
"𠮷".codePointAt(0) //20bb7
Copy the code
If you combine the resulting Unicode encodings:
"\u{20bb7}" / / "𠮷"
Copy the code
For more information on how to use Unicode, see my Unicode Guide.
New object methods
ES2015 introduces some static methods under the Object class:
Object.is()
Determine if the two values are the sameObject.assign()
Used to make a shallow copy of an objectObject.setPrototypeOf
Sets the prototype of an object
Object.is()
This method is used to help compare the values of objects:
Usage:
Object.is(a, b)
Copy the code
The return value is always false except for:
a
和b
It’s the same objecta
和b
Are equal strings (strings combined with the same characters are equal)a
和b
It’s the same numbera
和b
Are allundefined
.null
.NaN
.true
Or arefalse
0 and -0 are different values in JavaScript, so be careful in this case (for example, using the + unary operator to convert all values to +0 before comparing).
Object.assign()
Introduced in the ES2015 version, this method copies all enumerable self properties from a given object into another object.
The basic use of this API is to create a shallow copy of an object.
const copied = Object.assign({}, original)
Copy the code
As a shallow copy, the value is copied, and the object copies its reference (not the object itself), so when you change an attribute value of the source object, the change also takes effect in the copied object, because the internal reference object is the same. :
const original = {
name: 'Fiesta'.car: {
color: 'blue'}}const copied = Object.assign({}, original)
original.name = 'Focus'
original.car.color = 'yellow'
copied.name //Fiesta
copied.car.color //yellow
Copy the code
As I mentioned earlier, source objects can be one or more:
const wisePerson = {
isWise: true
}
const foolishPerson = {
isFoolish: true
}
const wiseAndFoolishPerson = Object.assign({}, wisePerson, foolishPerson)
console.log(wiseAndFoolishPerson) //{ isWise: true, isFoolish: true }
Copy the code
Object.setPrototypeOf()
Sets the prototype of an object. You can accept two parameters: the object and the prototype.
Usage:
Object.setPrototypeOf(object, prototype)
Copy the code
Example:
const animal = {
isAnimal: true
}
const mammal = {
isMammal: true
}
mammal.__proto__ = animal
mammal.isAnimal //true
const dog = Object.create(animal)
dog.isAnimal //true
console.log(dog.isMammal) //undefined
Object.setPrototypeOf(dog, mammal)
dog.isAnimal //true
dog.isMammal //true
Copy the code
Expansion operator
You can expand an array, an object, or even a string by using the expansion operator… .
Let’s take an array as an example and give:
const a = [1.2.3]
Copy the code
You can create a new array as follows:
const b = [...a, 4.5.6]
Copy the code
You can also create a copy of the array as follows:
const c = [...a]
Copy the code
This approach is still valid for objects. Clone an object as follows:
constnewObj = { ... oldObj }Copy the code
When used on strings, the expansion operator creates an array of each character in the string:
const hey = 'hey'
const arrayized = [...hey] // ['h', 'e', 'y']
Copy the code
This operator has some very useful applications. One of the most important is the ability to use arrays as function arguments in a very simple way:
const f = (foo, bar) = > {}
const a = [1.2] f(... a)Copy the code
(In the previous syntax specification, you could only do this with f.ply (null, a), which was not very friendly or readable.)
Residual arguments (rest elements) are useful when used in conjunction with array destructuring.
const numbers = [1.2.3.4.5]
[first, second, ...others] = numbers
Copy the code
Here are spread elements:
const numbers = [1.2.3.4.5]
const sum = (a, b, c, d, e) = > a + b + c + d + e
constsum = sum(... numbers)Copy the code
ES2018 introduces residual properties, the same operator but only for objects.
Rest Properties:
const{ first, second, ... others } = {first: 1.second: 2.third: 3.fourth: 4.fifth: 5
}
first / / 1
second / / 2
others // { third: 3, fourth: 4, fifth: 5 }
Copy the code
Spread properties allow us to combine properties with… The attributes of the object after the operator:
constitems = { first, second, ... others } items//{ first: 1, second: 2, third: 3, fourth: 4, fifth: 5 }
Copy the code
Set
A Set data structure allows us to add data to a container.
A Set is a collection of objects or underlying data types (strings, numbers, or Booleans). You can think of it as a Map, where values are the mapping keys and the Map value is always true.
Initialize a Set
A Set can be initialized as follows:
const s = new Set(a)Copy the code
Add an item to the Set
You can add items to a Set using the add method:
s.add('one')
s.add('two')
Copy the code
Set stores only unique elements, so multiple calls to s.dd (‘one’) do not repeatedly add new elements.
You cannot add more than one element to a set at the same time. You need to call the add() method multiple times.
Check if the element is in the set
We can check if an element is in a set by:
s.has('one') //true
s.has('three') //false
Copy the code
Remove an element from a set:
Using the delete() method:
s.delete('one')
Copy the code
Determines the number of elements in a set
Use the size attribute:
s.size
Copy the code
Delete all elements from set
Using the clear() method:
s.clear()
Copy the code
Iterate over set
Use keys() or values() methods – these are equivalent to the following code:
for (const k of s.keys()) {
console.log(k)
}
for (const k of s.values()) {
console.log(k)
}
Copy the code
The Entries () method returns an iterator, which you can use as follows:
const i = s.entries()
console.log(i.next())
Copy the code
Calling i.ext () will return each element as a {value, done = false} object until the end of the iteration, when done is true.
You can also call the forEach() method of set:
s.forEach(v= > console.log(v))
Copy the code
Or you can just use for.. Of loop:
for (const k of s) {
console.log(k)
}
Copy the code
Initialize a set with some initializers
You can initialize a set with some values:
const s = new Set([1.2.3.4])
Copy the code
Convert a set to an array
const a = [...s.keys()]
// or
const a = [...s.values()]
Copy the code
WeakSet
A WeakSet is a special Set.
In a set, elements are not gc (garbage collection). A weakSet makes all of its elements gc ready. Each key in weakSet is an object. When the reference to this object disappears, the corresponding value can be gc.
Here are the main differences:
- WeakSet is not iterative
- You can’t empty all elements in weakSet
- Cannot get the size of weakSet
A weakSet is usually used in framework-level code and only exposes the following methods:
- add()
- has()
- delete()
Map
A map structure of data allows us to establish relationships between data and keys
Before the ES6
Before the introduction of Map, developers usually used objects as maps, associating an Object or value value with a specified key:
const car = {}
car['color'] = 'red'
car.owner = 'Flavio'
console.log(car['color']) //red
console.log(car.color) //red
console.log(car.owner) //Flavio
console.log(car['owner']) //Flavio
Copy the code
After introducing Map
ES6 introduces Map data structures, which provide a suitable tool for working with such data structures
Map initialization:
const m = new Map(a)Copy the code
Add entries to the Map
You can set entries to a map using the set() method:
m.set('color'.'red')
m.set('age'.2)
Copy the code
Get entries from the map by key
You can retrieve items from the map using the get() method:
const color = m.get('color')
const age = m.get('age')
Copy the code
Delete entries from the map by key
Using the delete() method:
m.delete('color')
Copy the code
Delete all entries from the map
Using the clear() method:
m.clear()
Copy the code
Check whether the map contains an entry by the key value
Use the has() method
const hasColor = m.has('color')
Copy the code
Gets the number of entries in the map
Use the size attribute:
const size = m.size
Copy the code
Initialize a map with value
You can initialize a map with a set of values:
const m = new Map([['color'.'red'], ['owner'.'Flavio'], ['age'.2]])
Copy the code
The key value of the Map
Any value (object, array, string, number) can be used as a map value (in the form of key-value keys), and any value can be used as a key, even an object.
If you want to get a nonexistent key from the map using the get() method, it will return undefined
Weird situations you’d be unlikely to find in the real world
const m = new Map()
m.set(NaN.'test')
m.get(NaN) //test
const m = new Map()
m.set(+0.'test')
m.get(0) //test
Copy the code
Use the Iterate iterator to get the keys of the map
Map provides the keys() method, which allows us to iterate over all keys:
for (const k of m.keys()) {
console.log(k)
}
Copy the code
Use the Iterate iterator to get the map values
Map provides the values() method, through which we can iterate out all values:
for (const v of m.values()) {
console.log(v)
}
Copy the code
Retrieves key-value pairs using the Iterate iterator
Map provides the entries() method, through which we can iterate out all key-value pairs:
for (const [k, v] of m.entries()) {
console.log(k, v)
}
Copy the code
The use method can also be simplified as:
for (const [k, v] of m) {
console.log(k, v)
}
Copy the code
Convert the map keys to an array
const a = [...m.keys()]
Copy the code
Convert map values to arrays
const a = [...m.values()]
Copy the code
WeakMap
WeakMap is a special Map
In a map object, data defined on it will never be garbage collected. WeakMap instead allows the data defined on it to be garbage collected freely. Each key of WeakMap is an object, and when the pointer to the object is lost, the corresponding value will be garbage collected.
This is the main difference of WeakMap:
- You cannot iterate over keys and values (or key-value pairs) on WeakMap.
- You cannot remove all items from WeakMap
- You cannot get the size of WeakMap
WeakMap provides the following methods, which are used in the same way as in Map:
get(k)
set(k, v)
has(k)
delete(k)
The use case for WeakMap is not as obvious as the Map use case, and you will probably never use it anywhere, but as a practical matter, WeakMap can build memory-sensitive caches that don’t interfere with the garbage collection mechanism, as well as meet the need for encapsulation rigor and information hiding.
Generators generator
Generators are a special function that can pause its own execution and resume after a certain period of time, allowing other code to run in the meantime (see the complete “javascript Generator Guide” for details on this topic).
Generators’ code decides that it must wait, so it allows other code in the queue to run, reserving the right to resume its operation “when what it’s waiting for” is done.
All of this is done with a simple keyword, ‘yield’. Execution stops when the generator contains the keyword.
Generator generators can contain a number of yield keywords to stop themselves multiple times, which is identified by the *function keyword (not to be confused with the dereferencing operators used in low-level languages such as C, C++, or Go).
Generators support new programming paradigms in JavaScript, including:
- Supports bidirectional communication when the Generator is running
- Does not “freeze” a while loop that runs long in a program
Here is an example explaining how the generator works:
function *calculator(input) {
var doubleThat = 2 * (yield (input / 2))
var another = yield (doubleThat)
return (input * doubleThat * another)
}
Copy the code
Let’s initialize it first:
const calc = calculator(10)
Copy the code
We then begin iterator iteration in generator:
calc.next()
Copy the code
The first iterator starts the iteration and returns the following object:
{
done: false
value: 5
}
Copy the code
Here’s how it works: The code runs the function and passes input=10 to the generator constructor, which runs until yield is reached and returns the yield output: input / 2 = 5, so we get a value of 5 and tell the iterator that it hasn’t done yet (the function just paused).
At the second iteration, we type 7:
calc.next(7)
Copy the code
Then we get the result:
{
done: false
value: 14
}
Copy the code
7 is used as the doubleThat value. Note that you might take input/2 as an input parameter, but this is only the return value for the first iteration. Now we ignore it, use the new input value 7, and multiply it by 2.
Then, we get the second yield value, which returns doubleThat, so the return value is 14.
For the next and final iterator, we type 100
calc.next(100)
Copy the code
In this way we get:
{
done: true
value: 14000
}
Copy the code
When the iterator completes (with no more yield keywords), we return input * doubleThat * another, which is equivalent to 10 * 14 * 100.
These are all features introduced in ES2015, but now let’s take a closer look at ES2016, which has a much smaller scope.
Array.prototype.includes()
This feature introduces a more concise syntax for checking whether an array contains a specified element.
For ES6 and earlier, to check whether an array contains a specified element, you have to use the indexOf method, which checks the index in the array. If the element does not exist, it returns -1. Since -1 evaluates to true, you need to reverse it, as shown in the following example:
if(! [1.2].indexOf(3)) {
console.log('Not found')}Copy the code
With the new features introduced in ES7, we can do this:
if(! [1.2].includes(3)) {
console.log('Not found')}Copy the code
Exponentiation operator
The exponentiation operator ** is equivalent to the math.pow () method, but it is not a library, but a language mechanism:
Math.pow(4.2) = =4支那2
Copy the code
This feature is a nice enhancement for mathematically intensive programs, where ** operators are standard in many languages (including Python, Ruby, MATLAB, Perl, and many others).
These are all features introduced in 2016, so let’s move on to 2017.
String padding
The purpose of string padding is to add characters to a string so that it reaches a specified length.
ES2017 introduces two String methods: padStart() and padEnd().
padStart(targetLength [, padString])
padEnd(targetLength [, padString])
Copy the code
Use examples:
Object.values()
This method returns an array containing all the properties of the object itself, as follows:
const person = { name: 'Fred'.age: 87 }
Object.values(person) // ['Fred', 87]
Copy the code
Object.values() can also apply to arrays:
const people = ['Fred'.'Tony']
Object.values(people) // ['Fred', 'Tony']
Copy the code
Object.entries()
This method returns an array containing all of the object’s own attribute key-value pairs. It is an array of the form [key, value], as follows:
const person = { name: 'Fred'.age: 87 }
Object.entries(person) // [['name', 'Fred'], ['age', 87]]
Copy the code
Object.entries() can also be used on arrays:
const people = ['Fred'.'Tony']
Object.entries(people) // [['0', 'Fred'], ['1', 'Tony']]
Copy the code
Object.getOwnPropertyDescriptors()
This method returns all of its (non-inherited) property descriptors. Any object in JavaScript has a set of properties, and each property has a descriptor. A descriptor is a set of attributes for an attribute, consisting of the following parts:
- Value: a familiar value
- Writable: Whether the property can be changed
- Get: The getter function for the property, called when the property is read
- Set: the setter function for the property, called when the property sets a value
- If the 64x is false, the property cannot be deleted, and any property other than its value cannot be changed.
- Enumerable: Whether this property can be enumerable
Object. GetOwnPropertyDescriptors (obj) accept an Object, and returns an Object with a descriptor set.
In what way is this useful?
ES6 gives us the object.assign () method, which copies all enumerable property values from one or more objects and returns a new Object.
However, there is a problem with this, because it does not correctly copy an attribute with a non-default attribute value.
If the Object has only one setter, then it will not correctly copy to a new Object. Use object.assign () to do the following:
const person1 = {
set name(newName) {
console.log(newName)
}
}
Copy the code
This will not work:
const person2 = {}
Object.assign(person2, person1)
Copy the code
But this will work:
const person3 = {}
Object.defineProperties(person3,
Object.getOwnPropertyDescriptors(person1))
Copy the code
With a simple console, you can view the following code:
person1.name = 'x'
"x"
person2.name = 'x'
person3.name = 'x'
"x"
Copy the code
Person2 has no setter, which cannot be copied in, and the shallow copy qualification for the Object is also present in the ** object.create ()** method.
The tail comma
This feature allows a trailing comma when a function is defined, and a trailing comma when a function is used:
const doSomething = (var1, var2,) = > {
/ /...
}
doSomething('test2'.'test2'.)Copy the code
This change will encourage developers to stop the ugly habit of writing commas at the beginning of a line
An asynchronous function
JavaScript has evolved from callback functions to Promise functions (ES2015) in a very short time, and since ES2017 the async/ Wait syntax of asynchronous JavaScript has become much simpler. An asynchronous function is a combination of a Promise and a generator. Basically, it is a higher-level abstraction than a Promise, and I repeat the general: async/await is built based on a Promise
Why async/await
It reduces references around promises and breaks the promise “don’t break the chain call” constraint.
When Promise was introduced in ES2015, it was meant to solve the problem of asynchronous code, and it did, but in the two years between ES2015 and ES2017, it became clear that Promise wasn’t the ultimate solution.
Promise was introduced to solve the famous callback hell, but it also introduces its own usage and syntactic complexities.
Promise was a nice native feature around which developers could explore better syntax, so when the time came, we got async functions
Async functions make code look like synchronous functions, but behind the scenes they are asynchronous and non-blocking.
How it works
An async function returns a promise, as in the following example:
const doSomethingAsync = (a)= > {
return new Promise(resolve= > {
setTimeout((a)= > resolve('I did something'), 3000)})}Copy the code
When you want to call this function, you put a wait in front of it, and the call is stopped until the promise is resolved or rejected. Note that the outer function must be defined as async. Here’s an example:
const doSomething = async() = > {console.log(await doSomethingAsync())
}
Copy the code
A hands-on example
Here is a simple example of an asynchronous function with async/await:
const doSomethingAsync = (a)= > {
return new Promise(resolve= > {
setTimeout((a)= > resolve('I did something'), 3000)})}const doSomething = async() = > {console.log(await doSomethingAsync())
}
console.log('Before')
doSomething()
console.log('After')
Copy the code
The above code will print the following result in the browser’s console:
Before
After
I did something //after 3s
Copy the code
On the Promise
Marking async keyword on any function means that the function will return a Promise, even if the function does not explicitly return a Promise internally, which is why the following code works:
const aFunction = async() = > {return 'test'
}
aFunction().then(alert) // This will alert 'test'
Copy the code
The same goes for the following example:
const aFunction = async() = > {return Promise.resolve('test')
}
aFunction().then(alert) // This will alert 'test'
Copy the code
Easier to read code
As in the example above, we compare it to a normal callback or chained function, and our code looks very simple.
This is a simple example, and when the code is complex enough, it generates more revenue.
For example, use a Promise to get a JSON resource and parse it:
const getFirstUserData = (a)= > {
return fetch('/users.json') // get users list
.then(response= > response.json()) // parse JSON
.then(users= > users[0]) // pick first user
.then(user= > fetch(`/users/${user.name}`)) // get user data
.then(userResponse= > response.json()) // parse JSON
}
getFirstUserData()
Copy the code
Here is an example of doing the same thing with async/await:
const getFirstUserData = async() = > {const response = await fetch('/users.json') // get users list
const users = await response.json() // parse JSON
const user = users[0] // pick first user
const userResponse = await fetch(`/users/${user.name}`) // get user data
const userData = await user.json() // parse JSON
return userData
}
getFirstUserData()
Copy the code
Serial multiple asynchronous functions
Async functions are very easy, and their syntax is much more readable than Promise.
const promiseToDoSomething = (a)= > {
return new Promise(resolve= > {
setTimeout((a)= > resolve('I did something'), 10000)})}const watchOverSomeoneDoingSomething = async() = > {const something = await promiseToDoSomething()
return something + ' and I watched'
}
const watchOverSomeoneWatchingSomeoneDoingSomething = async() = > {const something = await watchOverSomeoneDoingSomething()
return something + ' and I watched as well'
}
watchOverSomeoneWatchingSomeoneDoingSomething().then(res= > {
console.log(res)
})
Copy the code
Print result:
I did something and I watched and I watched as well
Copy the code
Easier debugging
Debugging promises is difficult because the debugger can’t cross asynchronous code, but debugging async/await is very simple and the debugger will handle it as if it were synchronous code.
Shared memory and atoms
WebWorkers can create multithreaded programs in a browser.
They pass messages in the form of events, and starting with ES2017, you can use SharedArrayBuffer to share an array of memory between each Worker and their creator.
Atomics avoids race conditions because it is not known how long it takes to write parts of memory to broadcast, so any type of write is completed when the value is read.
More details about it can be found in the proposal.
This is ES2017, and I’m going to introduce the features of ES2018.
Rest/Spread Properties
ES2015 introduces methods for deconstructing arrays when you use:
const numbers = [1.2.3.4.5]
[first, second, ...others] = numbers
Copy the code
And expand parameters:
const numbers = [1.2.3.4.5]
const sum = (a, b, c, d, e) = > a + b + c + d + e
constsum = sum(... numbers)Copy the code
ES2018 introduces the same functionality for objects.
Deconstruction:
const{ first, second, ... others } = {first: 1.second: 2.third: 3.fourth: 4.fifth: 5 }
first / / 1
second / / 2
others // { third: 3, fourth: 4, fifth: 5 }
Copy the code
Expand properties allow new objects to be created by combining object properties passed after the expand operator:
constitems = { first, second, ... others } items//{ first: 1, second: 2, third: 3, fourth: 4, fifth: 5 }
Copy the code
Asynchronous iterator
For-await-of allows you to iterate through loops using asynchronous iterables:
for await (const line of readLines(filePath)) {
console.log(line)
}
Copy the code
Since it uses await, you can only use it in async functions.
Promise.prototype.finally()
This is a big pity. When a Promise is fulfilled, it will invoke then one after another.
If an error occurs during this process, then is skipped and a catch is executed.
And finally() allows you to run some code, with or without success:
fetch('file.json')
.then(data= > data.json())
.catch(error= > console.error(error))
.finally((a)= > console.log('finished'))
Copy the code
Regular expression improvement
ES2018 to regular expressions, introduced many improvements, these can be in flaviocopes.com/javascript-… Found on.
Here are some specific additions to the ES2018 regular expression improvements:
RegExp lookbehind assertions: Matches a string based on previous assertions
Is this a Lookahead: what can you use? = to match a string, followed by a specific string:
/Roger(? =Waters)//Roger(? = Waters)/.test('Roger is my dog') //false/Roger(? = Waters)/.test('Roger is my dog and Roger Waters is a famous musician') //true
Copy the code
? ! It is possible to do the reverse if the matching string is no instead of following a specific substring afterwards:
/Roger(? ! Waters)//Roger(? ! Waters)/.test('Roger is my dog') //true/Roger(? ! Waters)/.test('Roger Waters is a famous musician') //false
Copy the code
Lookaheads used? = Symbol, they are ready to use.
Is Lookbehinds a new feature to use? < =.
/ (?<=Roger) Waters/ / (? < =Roger) Waters/.test('Pink Waters is my dog/ / ')false/ (? < =Roger) Waters/.test('Roger is my dog and Roger Waters is a famous musician/ / ')true
Copy the code
If a lookbehind is negative, use? >! :
/ (?<! Roger) Waters/ / (? <!Roger) Waters/.test('Pink Waters is my dog/ / ')true/ (? <!Roger) Waters/.test('Roger is my dog and Roger Waters is a famous musician/ / ')false
Copy the code
Unicode attribute escape\ p {... }
and \ P {... }
In regular expression mode, you can use \d to match any number, \s to match any string that isn’t a space, \w to match any alphanumeric string, and so on.
This new feature extends this concept to all Unicode characters introducing \p{}
and is negation \P{}
.
This new feature extends unicode characters, introducing \p{} for handling
Any Unicode character has a set of attributes, such as the script acknowledgment language, and ASCII is a Boolean value used to check for ASCII characters. You can place this attribute in () and the regular expression will check to see if it is true.
/^\p{ASCII}+$/u.test('abc') / / ✅
/^\p{ASCII}+$/u.test('ABC@') / / ✅
/^\p{ASCII}+$/u.test('ABC 🙃') / / ❌
Copy the code
ASCII_Hex_Digit is another Boolean value used to check if the string contains a valid hexadecimal number:
/^\p{ASCII_Hex_Digit}+$/u.test('0123456789ABCDEF') / / ✅
/^\p{ASCII_Hex_Digit}+$/u.test('h') / / ❌
Copy the code
In addition, there are many other attributes. You can check them by adding their names to (), including Uppercase, Lowercase, White_Space, Alphabetic, Emoji, and more:
/^\p{Lowercase}$/u.test('h') / / ✅
/^\p{Uppercase}$/u.test('H') / / ✅
/^\p{Emoji}+$/u.test('H') / / ❌
/^\p{Emoji}+$/u.test('🙃 🙃') / / ✅
Copy the code
In addition to binary attributes, you can also check any Unicode character attributes to match specific values, in this case I check if the string is written in Greek or Latin:
/^\p{Script=Greek}+$/u.test('epsilon lambda lambda eta argument ι kappa ά predominate') / / ✅
/^\p{Script=Latin}+$/u.test('hey') / / ✅
Copy the code
Reading github.com/tc39/propos… Gets details about using all attributes.
Named capturing groups
In ES2018 a capturing group can be assigned to a name, rather than just being assigned a slot in the result array:
const re = / (?
\d{4})-(?
\d{2})-(?
\d{2})/
const result = re.exec('2015-01-02')
// result.groups.year === '2015';
// result.groups.month === '01';
// result.groups.day === '02';
Copy the code
The s
flag for regular expressions
The s
flag, short for single line, causes the .
to match new line characters as well. Without it, the dot matches regular characters but not the new line:
/hi.welcome/.test('hi\nwelcome') // false
/hi.welcome/s.test('hi\nwelcome') // true
Copy the code
ESNext
What is ESNext?
ESNext is a name that always points to the next version of JavaScript.
The current version of ECMAScript is ES2018, which was released in June 2018.
Historically, standardized versions of JavaScript have been released in the summer, so we can expect ECMAScript 2019 to be released in the summer of 2019.
So ES2018 has been released at the time of this writing, so ESNext refers to ES2019.
Proposals for the ECMAScript standard are organized in phases, with phases 1 through 3 being incubated for functionality, and phase 4 functionality finalized as part of the new standard.
At the time of writing this article, the major browsers implemented most of the features of Phase 4, so I’ll cover them in this article.
Some of these changes are mostly for internal use, but it’s also good to know what’s going on.
There are a few other phase 3 features that are likely to be upgraded to Phase 4 in the coming months, and you can check them out at this Github repository: github.com/tc39/propos… .
Array.prototype.{flat,flatMap}
Flat () is a new array instance method that converts multidimensional arrays into one-dimensional arrays.
Example:
['Dog'['Sheep'.'Wolf']].flat()
//[ 'Dog', 'Sheep', 'Wolf' ]
Copy the code
By default it can only convert a two-dimensional array to a one-dimensional array, but you can add a parameter to determine the level to expand. If you set this parameter to Infinity it will expand an infinite number of levels to a one-dimensional array:
['Dog'['Sheep'['Wolf']]].flat()
//[ 'Dog', 'Sheep', [ 'Wolf' ] ]
['Dog'['Sheep'['Wolf']]].flat(2)
//[ 'Dog', 'Sheep', 'Wolf' ]
['Dog'['Sheep'['Wolf']]].flat(Infinity)
//[ 'Dog', 'Sheep', 'Wolf' ]
Copy the code
If you’re familiar with the map method of arrays, you know that you can use it to perform a function on each element of an array.
FlatMap () is a new array instance method that combines flat() with map. This is useful when you want to do some processing in a map function, but still want the result to look like flat:
['My dog'.'is awesome'].map(words= > words.split(' '))
//[ [ 'My', 'dog' ], [ 'is', 'awesome' ] ]
['My dog'.'is awesome'].flatMap(words= > words.split(' '))
//[ 'My', 'dog', 'is', 'awesome' ]
Copy the code
Optional catch binding
Sometimes we don’t need to bind parameters to try/catch.
In the old days we had to do this:
try {
/ /...
} catch (e) {
//handle error
}
Copy the code
Even though we have never analyzed errors by e, we can now simply omit it:
try {
/ /...
} catch {
//handle error
}
Copy the code
Object.fromEntries()
Objects have an entries()
method, since ES2017.
Starting with ES2017, Object will have an entries() method.
It returns an array containing an array of all the object’s own attributes, such as [key, value] :
const person = { name: 'Fred'.age: 87 }
Object.entries(person) // [['name', 'Fred'], ['age', 87]]
Copy the code
ES2019 introduces a new object.fromentries () method that creates a new Object from the property array above:
const person = { name: 'Fred'.age: 87 }
const entries = Object.entries(person)
const newPerson = Object.fromEntries(entries) person ! == newPerson//true
Copy the code
String.prototype.{trimStart,trimEnd}
These features have been implemented in V8 /Chrome for almost a year and will be standardized in ES2019.
trimStart()
Delete the space at the beginning of the string and return a new string:
'Testing'.trimStart() //'Testing'
' Testing'.trimStart() //'Testing'
' Testing '.trimStart() //'Testing '
'Testing'.trimStart() //'Testing'
Copy the code
trimEnd()
Remove the space at the end of the string and return a new string:
'Testing'.trimEnd() //'Testing'
' Testing'.trimEnd() //' Testing'
' Testing '.trimEnd() //' Testing'
'Testing '.trimEnd() //'Testing'
Copy the code
Symbol.prototype.description
Now you can use description to get the value of Symbol instead of using the toString() method:
const testSymbol = Symbol('Test')
testSymbol.description // 'Test'
Copy the code
JSON improvements
The delimiter (\u2028) and delimiter (\u2029) are not allowed in the JSON string before this.
When using json.parse, these characters cause a SyntaxError, but now they parse correctly and as defined by the JSON standard.
Well-formed JSON.stringify()
Fixed json.stringify () when handling UTF-8 code points (U+D800 to U+DFFF).
Before the fix, calling json.stringify () will return a badly formed Unicode character, such as (a “�”).
Now you can safely convert it to a string using json.stringify (), and you can convert it back to its original representation using json.parse ().
Function.prototype.toString()
A function always has a toString method, which returns a string containing the function code.
ES2019 changes the return value to avoid stripping comments and other strings (such as Spaces) and to more accurately represent the function definition.
If previously we had
Maybe we used to have this:
function/ *this is bar* /bar () {}
Copy the code
Behavior at the time:
bar.toString() //'function bar() {}
Copy the code
Current behavior:
bar.toString(); // 'function /* this is bar */ bar () {}'
Copy the code
In conclusion, I hope this article has helped you get up to speed on some of the latest JavaScript and what we’ll see in 2019.
Click here to get a PDF / ePub / Mobi version of this post to read offline
Copyright
Copyright: Lightning Miners Translation group translation is for study, research and communication only. The copyright belongs to The Lightning Miners Translation Group, the author of the article and the translator. Non-commercial reprint is welcome. Please contact the translator or administrator for permission before reprinting, and clearly indicate the source of this article, translator, proofreader and full links to the Lightning Miners Translation Group at the beginning of the article, offenders will be corrected.