Aujourd'hui, dans la huitième partie de la traduction du manuel JavaScript, nous passerons en revue les fonctionnalités du langage qui y figurait après la sortie de la norme ES6. D'une manière ou d'une autre, nous avons rencontré plusieurs de ces opportunités plus tôt, quelque part en les approfondissant, quelque part en tenant pour acquis. Cette section du guide vise, avec la divulgation de certains sujets que nous n'avons pas abordés auparavant, à rationaliser les connaissances d'un développeur novice dans le domaine du JavaScript moderne.
→
Partie 1: premier programme, fonctionnalités linguistiques, normes→
Partie 2: style de code et structure du programme→
Partie 3: variables, types de données, expressions, objets→
Partie 4: caractéristiques→
Partie 5: tableaux et boucles→
Partie 6: exceptions, points-virgules, littéraux génériques→
Partie 7: mode strict, ce mot-clé, événements, modules, calculs mathématiques→
Partie 8: Présentation des fonctionnalités d'ES6→
Partie 9: Présentation des normes ES7, ES8 et ES9
À propos d'ES6
La norme ES6, qui serait plus correcte d'appeler ES2015 ou ECMAScript 2015 (ce sont ses noms officiels, bien que tout le monde l'appelle ES6), est apparue 4 ans après la publication de la norme précédente - ES5.1. Il a fallu une dizaine d'années pour développer tout ce qui entrait dans la norme ES5.1. De nos jours, tout ce qui figurait dans cette norme est devenu l'outil habituel du développeur JS. Il convient de noter que ES6 a apporté des modifications majeures à la langue (tout en conservant une compatibilité descendante avec ses versions précédentes). Afin d'apprécier l'ampleur de ces changements, on peut noter que la taille du document décrivant la norme ES5 est d'environ 250 pages, et la norme ES6 est décrite dans un document qui compte déjà environ 600 pages.
La liste des innovations les plus importantes de la norme ES2015 peut comprendre les éléments suivants:
- Fonctions fléchées
- Promesses
- Générateurs
- Mots
let
clés let
et const
- Cours
- Modules
- Support littéral de modèle
- Prise en charge des paramètres de fonction par défaut
- Opérateur de diffusion
- Affectation destructrice
- Amélioration des littéraux d'objets
for...of
boucle- Prise en charge des structures de données
Map
and Set
Considérez ces possibilités.
Fonctions fléchées
Les fonctions fléchées ont changé l'apparence du code JavaScript. En termes d'apparence, leur utilisation rend les déclarations de fonctions plus courtes et plus faciles. Voici la déclaration d'une fonction régulière.
const foo = function foo() {
Mais presque la même (mais pas complètement similaire à la précédente) fonction de flèche.
const foo = () => {
Si le corps de la fonction flèche se compose d'une seule ligne, dont le résultat doit être renvoyé par cette fonction, alors il est écrit encore plus court.
const foo = () => doSomething()
Si la fonction flèche ne prend qu'un seul paramètre, vous pouvez l'écrire comme suit.
const foo = param => doSomething(param)
Il est à noter qu'avec l'avènement des fonctions flèches, les fonctions ordinaires n'ont plus disparu, elles peuvent encore être utilisées dans le code, elles fonctionnent de la même manière qu'auparavant.
Ce mot-clé figure dans les fonctions fléchées
Les fonctions fléchées n'ont pas leur propre valeur, elles l'héritent du contexte d'exécution.
Cela corrige le problème, pour lequel, lors de l'utilisation de fonctions régulières, il était nécessaire d'utiliser des constructions comme
var that = this
pour préserver le contexte. Cependant, comme cela a été montré dans les parties précédentes du manuel, cette modification affecte sérieusement les caractéristiques de l'utilisation des fonctions fléchées et la portée de leur application.
Promesses
Les promesses vous permettent de vous débarrasser du problème bien connu appelé «enfer de rappel», bien que leur utilisation implique l'utilisation de structures assez complexes. Ce problème a été résolu dans la norme ES2017 avec l'avènement de la construction
async/await
, qui est basée sur des promesses.
Les développeurs JavaScript ont utilisé des promesses avant la norme ES2015, en utilisant diverses bibliothèques pour cela (par exemple - jQuery, q, deferred.js, vow). Cela indique l'importance et la pertinence de ce mécanisme. Différentes bibliothèques l'implémentent de différentes manières, l'émergence d'une norme dans ce domaine peut être considérée comme un fait très positif.
Voici le code écrit à l'aide des fonctions de rappel (rappels).
setTimeout(function() { console.log('I promised to run after 1s') setTimeout(function() { console.log('I promised to run after 2s') }, 1000) }, 1000)
En utilisant des promesses, cela peut être réécrit comme suit.
const wait = () => new Promise((resolve, reject) => { setTimeout(resolve, 1000) }) wait().then(() => { console.log('I promised to run after 1s') return wait() }) .then(() => console.log('I promised to run after 2s'))
Générateurs
Les générateurs sont des fonctions spéciales qui peuvent suspendre leur propre exécution et la reprendre. Cela permet à un autre code d'être exécuté pendant que le générateur est inactif.
Le générateur décide lui-même qu'il doit faire une pause et permettre à un autre code, "en attente" de son tour, de s'exécuter. Dans le même temps, le générateur a la possibilité de poursuivre son exécution après que l'opération, dont il attend les résultats, soit terminée.
Tout cela se fait grâce à un seul mot-clé simple de
yield
. Lorsque ce mot-clé est trouvé dans le générateur, son exécution est suspendue.
Un générateur peut contenir plusieurs lignes avec ce mot-clé, interrompant sa propre exécution plusieurs fois. Les générateurs sont déclarés à l'aide de la construction de
*function
. Cet astérisque devant le mot
function
ne doit pas être pris pour quelque chose comme un opérateur de déréférencement de pointeur utilisé dans des langages comme C, C ++ ou Go.
Les générateurs marquent l'avènement d'un nouveau paradigme de programmation JavaScript. En particulier, ils permettent l'échange de données bidirectionnel entre le générateur et un autre code, et permettent la création de boucles de longue durée de vie qui ne «suspendent» pas le programme.
Prenons un exemple illustrant les caractéristiques du fonctionnement des générateurs. Voici le générateur lui-même.
function *calculator(input) { var doubleThat = 2 * (yield (input / 2)) var another = yield (doubleThat) return (input * doubleThat * another) }
Avec cette commande, nous l'initialisons.
const calc = calculator(10)
Puis nous nous tournons vers son itérateur.
calc.next()
Cette commande démarre un itérateur, elle retourne un tel objet.
{ done: false value: 5 }
Ici, ce qui suit se produit. Le code exécute une fonction en utilisant la valeur d'
input
transmise au constructeur du générateur. Le code générateur est exécuté jusqu'à ce que le mot-clé
yield
soit trouvé. À ce stade, il renvoie le résultat de la division de l'
input
par
2
, ce qui, puisque l'
input
est
10
, donne le nombre
5
. Nous obtenons ce nombre grâce à l'itérateur et, avec lui, une indication que le générateur n'est pas encore terminé (la propriété
done
dans l'objet retourné par l'itérateur est définie sur
false
), c'est-à-dire que la fonction n'a été suspendue.
La prochaine fois que l'itérateur sera appelé, nous passerons le numéro
7
au générateur.
calc.next(7)
En réponse à cela, l'itérateur nous renvoie l'objet suivant.
{ done: false value: 14 }
Ici, le nombre
7
été utilisé pour calculer la valeur
doubleThat
.
À première vue, il peut sembler que le code d'
input / 2
ressemble à un argument d'une fonction, mais ce n'est que la valeur renvoyée à la première itération. Ici, nous sautons cette valeur et utilisons la nouvelle valeur d'entrée
7
, en la multipliant par
2
. Après cela, nous arrivons au deuxième mot clé
yield
, par conséquent, la valeur obtenue dans la deuxième itération est
14
.
À la prochaine itération, qui est la dernière, nous passons le nombre
100
au générateur.
calc.next(100)
En réponse, nous obtenons l'objet suivant.
{ done: true value: 14000 }
L'itération est terminée (le mot-clé
yield
ne se trouve plus dans le générateur), le résultat de l'évaluation de l'expression
(input * doubleThat * another)
retourné dans l'objet, soit -
10 * 14 * 100
et une indication de l'achèvement de l'itérateur (
done: true
).
Mots-clés let et const
JavaScript a toujours utilisé le mot clé
var
pour déclarer des variables. Ces variables ont une portée fonctionnelle. Les mots clés
let
et
const
, respectivement, vous permettent de déclarer des variables et des constantes qui ont une portée de bloc.
Cela signifie que, par exemple, une variable déclarée à l'aide du mot clé
let
dans une boucle, à l'intérieur d'un bloc
if
, ou à l'intérieur d'un bloc de code normal limité par des accolades, n'ira pas au-delà de ce bloc. Les variables déclarées avec
var
ne sont pas conservées dans de tels blocs, devenant disponibles dans la fonction au niveau de laquelle elles sont déclarées.
Le mot clé
const
fonctionne exactement comme
let
, mais avec lui, les constantes immuables sont déclarées.
Dans le code JS moderne, le mot-clé
var
est rarement utilisé. Il a cédé la place aux mots clés
let
et
const
. Dans le même temps, ce qui peut sembler inhabituel, le mot-clé
const
est très largement utilisé aujourd'hui, ce qui indique la popularité des idées d'immunité des entités dans la programmation moderne.
Cours
Il s'est avéré que JavaScript était le seul langage extrêmement répandu utilisant le modèle d'héritage prototype. Les programmeurs passant à JS à partir de langages qui implémentent le mécanisme d'héritage basé sur les classes se sentaient mal à l'aise dans un tel environnement. La norme ES2015 a introduit la prise en charge des classes en JavaScript. Il s'agit essentiellement de «sucre syntaxique» autour des mécanismes internes de JS utilisant des prototypes. Cependant, cela affecte la façon exacte dont les applications JS écrivent.
Les mécanismes d'héritage JavaScript ressemblent désormais à des mécanismes similaires dans d'autres langages orientés objet.
class Person { constructor(name) { this.name = name } hello() { return 'Hello, I am ' + this.name + '.' } } class Actor extends Person { hello() { return super.hello() + ' I am an actor.' } } var tomCruise = new Actor('Tom Cruise') console.log(tomCruise.hello())
Ce programme affiche le texte
Hello, I am Tom Cruise. I am an actor
sur la console
Hello, I am Tom Cruise. I am an actor
Hello, I am Tom Cruise. I am an actor
.
Dans les classes JS, les variables d'instance ne peuvent pas être déclarées; elles doivent être initialisées dans les constructeurs.
Constructeur de classe
Les classes ont une méthode spéciale,
constructor
, qui est appelée lorsqu'une instance de la classe est créée à l'aide du
new
mot clé.
▍ Mot-clé super
Le
super
mot
super
clé vous permet d'accéder à la classe parent à partir des classes descendantes.
▍ Getters et setters
Le getter d'une propriété peut être défini comme suit.
class Person { get fullName() { return `${this.firstName} ${this.lastName}` } }
Le passeur peut être décrit comme indiqué ci-dessous.
class Person { set age(years) { this.theAge = years } }
Ils travaillent avec des getters et des setters comme s'ils n'étaient pas des fonctions, mais des propriétés ordinaires des objets.
Modules
Avant la norme ES2015, il y avait plusieurs approches concurrentes pour travailler avec des modules. En particulier, nous parlons des technologies RequireJS et CommonJS. Cette situation a conduit à un désaccord dans la communauté des développeurs JS.
De nos jours, grâce à la standardisation des modules dans ES2015, la situation se normalise progressivement.
▍ Importer des modules
Les modules sont importés à l'aide d'une construction du formulaire
import...from...
Voici quelques exemples.
import * as something from 'mymodule' import React from 'react' import { React, Component } from 'react' import React as MyLibrary from 'react'
▍ Exportation de modules
Les mécanismes internes du module sont fermés du monde extérieur, mais à partir du module, vous pouvez exporter tout ce qu'il peut offrir à d'autres modules. Cela se fait à l'aide du mot-clé d'
export
.
export var foo = 2 export function bar() { }
▍ Littéraux de modèle
Les littéraux de modèle sont une nouvelle façon de décrire les chaînes en JavaScript. Voici à quoi ça ressemble.
const aString = `A string`
De plus, l'utilisation de la syntaxe des littéraux de modèle vous permet d'incorporer des expressions dans des chaînes et de les interpoler. Cela se fait en utilisant une construction de la forme
${a_variable}
. Voici un exemple simple de son utilisation:
const v = 'test' const str = `something ${v}`
Voici un exemple plus compliqué, illustrant la possibilité d'évaluer des expressions et de substituer leurs résultats dans une chaîne.
const str = `something ${1 + 2 + 3}` const str2 = `something ${foo() ? 'x' : 'y' }`
Grâce à l'utilisation de littéraux de modèle, il est devenu beaucoup plus facile de déclarer des chaînes multi-lignes.
const str3 = `Hey this string is awesome!`
Comparez cela avec ce que vous avez dû faire pour décrire les chaînes multilignes lors de l'utilisation des fonctionnalités disponibles dans la langue avant ES2015.
var str = 'One\n' + 'Two\n' + 'Three'
Paramètres de fonction par défaut
Désormais, les fonctions prennent en charge les paramètres utilisés par défaut - dans le cas où les arguments correspondants ne leur sont pas transmis lors de l'appel des fonctions.
const foo = function(index = 0, testing = true) { } foo()
Opérateur de diffusion
L'opérateur d'étalement (opérateur d'extension) vous permet de «développer» des tableaux, des objets ou des chaînes. Cet opérateur ressemble à trois points (
...
). Tout d'abord, considérez-le avec un exemple de tableau.
const a = [1, 2, 3]
Voici comment créer un nouveau tableau basé sur ce tableau.
const b = [...a, 4, 5, 6]
Voici comment créer une copie du tableau.
const c = [...a]
Cet opérateur fonctionne également avec les objets. Par exemple, voici comment l'utiliser pour cloner un objet.
const newObj = { ...oldObj }
En appliquant l'opérateur d'étalement à une chaîne, vous pouvez le convertir en un tableau, dont chaque élément contient un caractère de cette chaîne.
const hey = 'hey' const arrayized = [...hey]
Cet opérateur, en plus des variantes ci-dessus de son application, est pratique à utiliser lors de l'appel de fonctions qui attendent une liste normale d'arguments, en leur passant un tableau avec ces arguments.
const f = (foo, bar) => {} const a = [1, 2] f(...a)
Auparavant, cela se faisait à l'aide d'une construction de la forme
f.apply(null, a)
, mais un tel code est plus difficile à écrire et il est moins lisible.
Affectation destructrice
La technique d'assignation déstructurante permet, par exemple, de prendre un objet, d'en extraire certaines valeurs et de les placer dans des variables ou constantes nommées.
const person = { firstName: 'Tom', lastName: 'Cruise', actor: true, age: 54, } const {firstName: name, age} = person
Ici, les propriétés
firstName
et
age
sont récupérées de l'objet. La propriété
age
est écrite dans la constante déclarée avec le même nom et la propriété
firstName
, après extraction, tombe dans le
name
constant.
L'affectation destructive convient également pour travailler avec des tableaux.
const a = [1,2,3,4,5] const [first, second, , , fifth] = a
Les
first
,
second
et
fifth
constantes obtiennent respectivement les premier, deuxième et cinquième éléments du tableau.
Amélioration des littéraux d'objets
ES2015 a considérablement étendu la capacité de décrire des objets à l'aide de littéraux d'objets.
▍ Simplification de l'inclusion de variables dans les objets
Auparavant, pour affecter une variable à une propriété d'un objet, il était nécessaire d'utiliser la construction suivante.
const something = 'y' const x = { something: something }
Maintenant, la même chose peut être faite comme ça.
const something = 'y' const x = { something }
▍ Prototypes
Le prototype de l'objet peut maintenant être défini en utilisant la construction suivante.
const anObject = { y: 'y' } const x = { __proto__: anObject }
▍ Mot-clé super
En utilisant le
super
mot
super
clé, les objets peuvent accéder aux objets prototypes. Par exemple, pour appeler leurs méthodes qui portent le même nom que les méthodes de ces objets eux-mêmes.
const anObject = { y: 'y', test: () => 'zoo' } const x = { __proto__: anObject, test() { return super.test() + 'x' } } x.test()
▍ Noms de propriété calculés
Les noms de propriété calculés sont formés au stade de la création d'objet.
const x = { ['a' + '_' + 'b']: 'z' } x.a_b
Pour ... de boucle
En 2009, dans la norme ES5, des boucles
forEach()
sont apparues. Il s'agit d'une conception utile, dont l'inconvénient est le fait que de tels cycles sont très difficiles à interrompre. Le classique
for
boucle dans les situations où vous devez interrompre l'exécution de la boucle avant son achèvement normal est un choix beaucoup plus approprié.
Un
for...of
cycle est apparu dans ES2015, qui, d'une part, se distingue par sa syntaxe concise et la commodité de
forEach
, et d'autre part, il prend en charge la possibilité d'une sortie anticipée du cycle.
Voici quelques exemples
for...of
exemples
for...of
boucles.
Mapper et définir des structures de données
ES2015 a introduit les structures de données
Map
and
Set
(ainsi que leurs versions «faibles»
WeakMap
et
WeakSet
, dont l'utilisation améliore les performances du «garbage collector» - le mécanisme responsable de la gestion de la mémoire dans les moteurs JS). Ce sont des structures de données très populaires qui, avant l'apparition de leur implémentation officielle, devaient être imitées à l'aide des outils linguistiques disponibles.
Résumé
Aujourd'hui, nous avons passé en revue les caractéristiques de la norme ES2015, qui ont grandement influencé l'état actuel de la langue. Notre prochain sujet sera consacré aux fonctionnalités des normes ES2016, ES2017 et ES2018.
Chers lecteurs! Quelles innovations de la norme ES6 trouvez-vous les plus utiles?
