Qu'est-ce que la mission de déstructuration ?
L'affectation de déstructuration vous permet d'attribuer des valeurs de propriété de tableau et d'objet à une série de variables en utilisant une syntaxe similaire aux littéraux de tableau ou d'objet. Cette syntaxe est très concise et plus claire que l'accès aux propriétés traditionnel.
Accéder aux trois premiers éléments d'un tableau sans utiliser d'affectation de déstructuration :
var first = someArray[0]; var second = someArray[1]; var third = someArray[2]; var first = someArray[0]; var second = someArray[1]; var third = someArray[2];
Après avoir utilisé l'affectation de déstructuration, le code correspondant devient plus concis et lisible :
var [first, second, third] = someArray; var [first, second, third] = someArray;
SpiderMonkey (le moteur JavaScript de Firefox) prend déjà en charge la plupart des fonctionnalités d'affectation de déstructuration, mais pas complètement.
Affectation déstructurante de tableaux et d'objets itérables
Nous avons vu des exemples d'affectation de déstructuration de tableaux ci-dessus. La forme générale de cette syntaxe est :
[ variable1, variable2, ..., variableN ] = array; [ variable1, variable2, ..., variableN ] = array;
Cela attribuera les éléments correspondants du tableau à la variable1 à la variableN dans l'ordre. Si vous devez déclarer des variables en même temps, vous pouvez ajouter les mots-clés var, let ou const devant l'expression de déstructuration.
var [ variable1, variable2, ..., variableN ] = array; let [ variable1, variable2, ..., variableN ] = array; const [ variable1, variable2, ..., variableN ] = array; var [ variable1, variable2, ..., variableN ] = array; let [ variable1, variable2, ..., variableN ] = array; const [ variable1, variable2, ..., variableN ] = array;
En fait, vous pouvez emboîter à n'importe quelle profondeur :
var [foo, [[bar], baz]] = [1, [[2], 3]]; console.log(foo); // 1 console.log(bar); // 2 console.log(baz); // 3 var [foo, [[bar], baz]] = [1, [[2], 3]]; console.log(foo); // 1 console.log(bar); // 2 console.log(baz); // 3
De plus, il est possible de sauter certains éléments d'un tableau :
var [,,third] = ["foo", "bar", "baz"]; console.log(third); // "baz" var [,,third] = ["foo", "bar", "baz"]; console.log(third); // "baz"
Vous pouvez également utiliser une expression Rest pour capturer les éléments restants d'un tableau :
var [head, ...tail] = [1, 2, 3, 4]; console.log(tail); // [2, 3, 4] var [head, ...tail] = [1, 2, 3, 4]; console.log(tail); // [2, 3, 4]
Si le tableau sort des limites ou accède à un élément qui n'existe pas dans le tableau, vous obtiendrez la même valeur qu'en accédant via l'index du tableau : non défini.
console.log([][0]); // undefined var [missing] = []; console.log(missing); // undefined console.log([][0]); // undefined var [missing] = []; console.log(missing); // undefined
Notez que la méthode de déstructuration et d'affectation des tableaux s'applique également aux objets traversables :
function* fibs() { var a = 0; var b = 1; while (true) { yield a; [a, b] = [b, a + b]; } } var [first, second, third, fourth, fifth, sixth] = fibs(); console.log(sixth); // 5 function* fibs() { var a = 0; var b = 1; while (true) { yield a; [a, b] = [b, a + b]; } } var [first, second, third, fourth, fifth, sixth] = fibs(); console.log(sixth); // 5
Affectation déstructurante d'objets
L'affectation de déstructuration d'objet vous permet de lier des variables à différentes valeurs de propriété de l'objet. Précisez le nom de la propriété à lier, suivi de la variable à lier :
var robotA = { name: "Bender" }; var robotB = { name: "Flexo" }; var { name: nameA } = robotA; var { name: nameB } = robotB; console.log(nameA); // "Bender" console.log(nameB); // "Flexo" var robotA = { name: "Bender" }; var robotB = { name: "Flexo" }; var { name: nameA } = robotA; var { name: nameB } = robotB; console.log(nameA); // "Bender" console.log(nameB); // "Flexo"
Lorsque le nom de l'attribut lié est le même que le nom de la variable qui reçoit la valeur de l'attribut, il existe un autre sucre syntaxique :
var { foo, bar } = { foo: "lorem", bar: "ipsum" }; console.log(foo); // "lorem" console.log(bar); // "ipsum" var { foo, bar } = { foo: "lorem", bar: "ipsum" }; console.log(foo); // "lorem" console.log(bar); // "ipsum"
Comme les tableaux, ils peuvent également être imbriqués :
var complicatedObj = { arrayProp: [ "Zapp", { second: "Brannigan" } ] }; var { arrayProp: [first, { second }] } = complicatedObj; console.log(first); // "Zapp" console.log(second); // "Brannigan" var complicatedObj = { arrayProp: [ "Zapp", { second: "Brannigan" } ] }; var { arrayProp: [first, { second }] } = complicatedObj; console.log(first); // "Zapp" console.log(second); // "Brannigan"
Lors de la déstructuration d'un bien qui n'existe pas, vous obtiendrez undéfini :
var { missing } = {}; console.log(missing); // undefined var { missing } = {}; console.log(missing); // undefined
Il existe un autre piège potentiel lors de l'utilisation de l'affectation de déstructuration d'objets, il n'y a pas de déclaration de variable (pas de mot-clé var, let ou const) lors de l'affectation de déstructuration :
{ blowUp } = { blowUp: 10 }; // Syntax error { blowUp } = { blowUp: 10 }; // Syntax error
En effet, la syntaxe JavaScript indique au moteur que toute instruction commençant par { est un bloc d'instructions (par exemple, {console} est un bloc d'instructions légales. La solution consiste à envelopper l'intégralité de l'instruction avec une paire de parenthèses : <). 🎜>
({ safe } = {}); // No errors ({ safe } = {}); // No errors
Autres situations
Lorsque vous essayez de déstructurer null ou undefined, vous obtiendrez une erreur de type :
var {blowUp} = null; // TypeError: null has no properties var {blowUp} = null; // TypeError: null has no properties
var {wtf} = NaN; console.log(wtf); // undefined var {wtf} = NaN; console.log(wtf); // undefined
Valeur par défaut
var [missing = true] = []; console.log(missing); // true var { message: msg = "Something went wrong" } = {}; console.log(msg); // "Something went wrong" var { x = 3 } = {}; console.log(x); // 3 var [missing = true] = []; console.log(missing); // true var { message: msg = "Something went wrong" } = {}; console.log(msg); // "Something went wrong" var { x = 3 } = {}; console.log(x); // 3
Application pratique
Paramètres de fonction
function removeBreakpoint({ url, line, column }) { // ... } function removeBreakpoint({ url, line, column }) { // ... }
Objet de configuration
Pour améliorer l'exemple ci-dessus, nous pouvons fournir des valeurs par défaut pour les propriétés de l'objet à déstructurer. Ceci est très pratique pour les objets qui sont utilisés comme paramètres de configuration, car de nombreux éléments de configuration ont une valeur par défaut raisonnable. Par exemple, le deuxième paramètre de la méthode ajax de jQuery est un objet de configuration, que nous pouvons implémenter comme ceci :
jQuery.ajax = function (url, { async = true, beforeSend = noop, cache = true, complete = noop, crossDomain = false, global = true, // ... more config }) { // ... do stuff }; jQuery.ajax = function (url, { async = true, beforeSend = noop, cache = true, complete = noop, crossDomain = false, global = true, // ... more config }) { // ... do stuff };
Utilisé avec les itérateurs
var map = new Map(); map.set(window, "the global"); map.set(document, "the document"); for (var [key, value] of map) { console.log(key + " is " + value); } // "[object Window] is the global" // "[object HTMLDocument] is the document" var map = new Map(); map.set(window, "the global"); map.set(document, "the document"); for (var [key, value] of map) { console.log(key + " is " + value); } // "[object Window] is the global" // "[object HTMLDocument] is the document"
for (var [key] of map) { // ... } for (var [key] of map) { // ... } 只遍历值: for (var [,value] of map) { // ... } for (var [,value] of map) { // ... }
Renvoyer plusieurs valeurs
Renvoie un tableau et extrait la valeur de retour via une affectation de déstructuration :
function returnMultipleValues() { return [1, 2]; } var [foo, bar] = returnMultipleValues(); function returnMultipleValues() { return [1, 2]; } var [foo, bar] = returnMultipleValues();
function returnMultipleValues() { return { foo: 1, bar: 2 }; } var { foo, bar } = returnMultipleValues(); function returnMultipleValues() { return { foo: 1, bar: 2 }; } var { foo, bar } = returnMultipleValues();
function returnMultipleValues() { return { foo: 1, bar: 2 }; } var temp = returnMultipleValues(); var foo = temp.foo; var bar = temp.bar; function returnMultipleValues() { return { foo: 1, bar: 2 }; } var temp = returnMultipleValues(); var foo = temp.foo; var bar = temp.bar;
function returnMultipleValues(k) { k(1, 2); } returnMultipleValues((foo, bar) => ...); function returnMultipleValues(k) { k(1, 2); } returnMultipleValues((foo, bar) => ...);
导入 CommonJS 模块的指定部分
还没使用过 ES6 的模块吧,那至少使用过 CommonJS 吧。当导入一个 CommonJS 模块 X 时,模块提供的方法也许多余你实际使用的。使用解构赋值,你可以明确指定你需要使用模块的哪些部分:
const { SourceMapConsumer, SourceNode } = require("source-map"); const { SourceMapConsumer, SourceNode } = require("source-map");
如果你使用 ES6 的模块机制,你可以看到 import 声明时有一个类似的语法。
结论
我们看到,解构赋值在很多场景下都很实用。在 Mozilla,我们已经有很多经验。Lars Hansen 在 10 年前就向 Opera 引入了解构赋值,Brendan Eich 在稍微晚点也给 Firefox 添加了支持,最早出现在 Firefox 2 中。因此,解构赋值已经渗透到我们每天对 JS 的使用中,悄悄地使我们的代码更简短、整洁。