What is deconstruction?
Deconstruction is completely opposite to constructing data. For example, instead of constructing a new object or array, it splits the existing object or array one by one to extract the data you need.
ES6 uses a new pattern to match the numerical values you want to extract, and deconstruction assignment adopts this pattern. This pattern will map the data structure you are deconstructing, and only those data that match the pattern will be extracted.
The deconstructed data item is located in the assignment operator To the right of =, it can be any combination of arrays and objects, allowing for arbitrary nesting. There is no limit to the number of variables used to assign values to these data.
Array destruction
Array deconstruction uses an array as a data item, and you can extract the values from this array to assign values to one or more variables according to the array pattern (used to match the values you need from the array).
Array pattern is used to identify which values are what you want to extract based on the position of the values. It must be able to accurately map the structure of the array so that each variable in the array pattern is assigned a value corresponding to the position in the deconstructed array.
Let me give you a few examples to help us understand:
Array pattern example
Assign all the values in the array to individual variables
// Set array const avengers = ['Tony Stark', 'Steve Rogers', 'Natasha Romanoff']; // Deconstruct the array to a variable. The array pattern is located to the left of the assignment operator `=`, and the structured array is to the right of //. const [ironMan, cap, blackWidow] = avengers; // ironMan = 'Tony Stark' // cap = 'Steve Rogers' // blackWidow = 'Natasha Romanoff' // output ironMan: ironMan;
Extract all values except the first one
const avengers = ['Tony Stark', 'Steve Rogers', 'Natasha Romanoff']; // We don't need to use Tony const [, cap, blackWidow] = avengers; // ironMan = Error: undefined // cap = 'Steve Rogers' // blackWidow = 'Natasha Romanoff' // Output cap: cap;
Extract all values except the second one
const avengers = ['Tony Stark', 'Steve Rogers', 'Natasha Romanoff']; // cap missing const [ironMan, , blackWidow] = avengers; // ironMan = 'Tony Stark' // cap = Error: undefined // blackWidow = 'Natasha Romanoff' // Output blackWidow: blackWidow;
Extract all values except the last one
const avengers = ['Tony Stark', 'Steve Rogers', 'Natasha Romanoff']; // ironMan vs cap const [ironMan, cap] = avengers; // ironMan = 'Tony Stark' // cap = 'Steve Rogers' // blackWidow = Error: undefined // Output blackWidow: ironMan;
Nested arrays
This matching pattern also supports nested arrays, as long as the assignment operator = the array pattern on the left matches the array structure on the right. Let me explain again that the variables on the left will be assigned the value corresponding to the position in the array on the right. No matter how deeply you nest them, you can still deconstruct them.
Deconstructing nested arrays
// Destructuring Nested Arrays const avengers = [ 'Natasha Romanoff', ['Tony Stark', 'James Rhodes'], ['Steve Rogers', 'Sam Wilson'] ]; // Avengers and their partners const [blackWidow, [ironMan, warMachine], [cap, falcon]] = avengers; // blackWidow = 'Natasha Romanoff' // ironMan = 'Tony Stark' // warMachine = 'James Rhodes' // cap = 'Steve Rogers' // falcon = 'Sam Wilson' // Output warMachine: warMachine;
Extract a value from a deeply nested array
// Extract Pepper Potts const avengers from this array = [ 'Natasha Romanoff', [['Tony Stark', 'Pepper Potts'], 'James Rhodes'], ['Steve Rogers', 'Sam Wilson'] ]; // Destructure const [ , // Skip 'Natasha Romanoff' [[ , // Skip 'Tony Stark' her // Pepper Potts assign to the variable 'hera' ]]] = avengers; // Please note: you can also write this way // const [, [[, hera ]]] = avengers; // Output hera: hera; // hera = 'Pepper Potts'
Use the rest operator to capture all remaining items
If you want to get a specific array item and put the remaining items into an array, you can use the rest operator to deconstruct it like this:
// Deconstruct const avengers through rest operator = ['Natasha Romanoff', 'Tony Stark', 'Steve Rogers']; const [blackWidow, ...theOthers] = avengers; theOthers; // blackWidow = 'Natasha Romanoff' // theOthers = ['Tony Stark', 'Steve Rogers'] // Output theOthers: theOthers;
Object destruction
Object deconstruction is even more magical, especially when you need to take values from a complex, deeply nested object, which is more obvious. To reiterate, object deconstruction and array deconstruction use the same rules (that is, create an object pattern on the left side of the assignment operator, so that its variable position matches the value position of the object on the right side).
In object destruction, you need to specify the attribute names that need to be extracted and the variable names that will be assigned. Like array deconstruction, we need to create an object pattern to map the deconstructed object on the left side of the assignment operator.
Although in this case, what we want to extract is the value of the object property (such as: we extract value from { prop: value }). Accordingly, our object pattern must have a variable, and the position of this variable must be consistent with the position of the property value we are about to extract.
Simple example
Extract a simple object attribute value
We can do this to assign the value of the property ironMan of object { ironMan: 'Tony Stark' } 'Tony Stark' the variable a :
//Deconstruct the property value of the object and assign it to a single variable `a`: const { ironMan: a } = { ironMan: 'Tony Stark' }; // Output a: a; // a = 'Tony Stark 'Extract multiple attribute values
As long as we expand the same pattern, we can extract multiple attribute values from an object, as follows:
// Setup our object const avengers = { ironMan: 'Tony Stark', cap: 'Steve Rogers', blackWidow: 'Natasha Romanoff' }; // Destructure object to individual variables const { ironMan: a, cap: b, blackWidow: c } = avengers; // a = 'Tony Stark ' // b = 'Steve Rogers' // c ='Natasha Romanoff' // Output a: a;Observe how this deconstruction pattern matches exactly the deconstructed object.
Nested object destruction
Like deconstructing nested arrays, we can deconstruct nested objects, no matter how deep they are.
// Setup our object const avengers = { blackWidow: 'Natasha Romanoff', ironManCharacters: { couple: { ironMan: 'Tony Stark', hera: 'Pepper Potts', }, partner: { warMachine: 'James Brodie' } }, capCharacters: { cap: 'Steve Rogers', partner: { falcon: 'Sam Wilson' } } }; // Destructure object to individual variables const { blackWidow: a, ironManCharacters: { couple: { ironMan: b, hera: c }, partner: { warMachine: d } }, capCharacters: { cap: e, partner: { falcon: f } } } = avengers; // a = 'Natasha Romanoff' // b = 'Tony Stark ' // c = 'Pepper Potts' // d = 'James Brodie' // e = 'Steve Rogers' // f = 'Sam Wilson' // Output a: a;Name the assigned variable
Of course, it is bad to set variable names like a, b, c , and variable names should make sense.
Long-lasting naming
// Setup our object const avengers = { ironMan: 'Tony Stark', cap: 'Steve Rogers', blackWidow: 'Natasha Romanoff' }; // Destructure object to individual variables with meaningful names const { ironMan: ironMan, cap: cap, blackWidow: blackWidow } = avengers; // blackWidow = 'Natasha Romanoff' // ironMan = 'Tony Stark ' // cap = 'Steve Rogers' // Output blackWidow: blackWidow; This approach is better than the above name a, b, and c , but it can still be improved. { ironMan: ironMan } looks a bit ugly and not intuitive.
Syntactically named shortcuts
If you want to assign the attribute value of an object to a variable, and the name of the variable is the same as the attribute name of the object, then in the assignment mode on the left side of = , you only need to simply write the attribute name, as follows:
// Setup our object const avenger = { ironMan: 'Tony Stark' }; // Destructure object to individual variables with meaningful names const { ironMan // equivalent to 'ironMan: ironMan' } = avenger; // ironMan = 'Tony Stark ' // Output ironMan: ironMan;Since the deconstructed object attribute name is the same as the assigned variable name, we only need to list the name once.
Concise grammar
Let's retweet the previous code a little to make them look more concise and clear:
// Setup our object const avengers = { ironMan: 'Tony Stark', cap: 'Steve Rogers', blackWidow: 'Natasha Romanoff' }; // Destructure object to individual variables with meaningful names const { ironMan, cap, blackWidow } = avengers; // Output ironMan: ironMan;Extract a deeply nested property from an object
Things are even more interesting when we want to extract a deeply nested object property:
// Setup our objectconst avengers = { blackWidow: 'Natasha Romanoff', ironManCharacters: { couple: { ironMan: 'Tony Stark', hera: 'Pepper Potts', }, partner: { warMachine: 'James Brodie' } }, capCharacters: { cap: 'Steve Rogers', partner: { falcon: 'Sam Wilson' } }};// Destructure a deeply nested objectconst { ironManCharacters: { couple } } = avengers;// couple = {// ironMan: 'Tony Stark', // hera: 'Pepper Potts',// }// Output couple:couple;Wait, how did you read this code? How is the variable couple defined?
By splitting this way, we can see that the assignment operator = on the left is a map of the deconstructed object:
const avengers = { ironManCharacters: { couple: { ironMan: 'Tony Stark', hera: 'Pepper Potts', } }};const { ironManCharacters: { couple }} = avengers;// Output couple:couple; Just using const { couple } = avengers; there is no way to extract the value of couple . Only by mapping the location and name of the object attribute to be extracted can the JS compiler obtain the corresponding information, search down along all the attributes of the object, and accurately extract the value we want.
It should also be noted here that couple uses syntax shortcuts to name variables, which is actually like this:
const { ironManCharacters: { couple: couple }} = avengers;This is how couple is defined, and its value is the value whose attribute name couple in the object avengers .
Deconstruct the object's attributes
So far, we have deconstructed the value of the object to assign values to a single variable, and in fact we can also assign values to the properties of another object.
const avengers = { blackWidow: 'Natasha Romanoff', ironManCharacters: { couple: { ironMan: 'Tony Stark', hera: 'Pepper Potts' } }};const ironManProperties = { family: {}};({ ironManCharacters: { couple: ironManProperties.family }} = avengers); ironManProperties.family// ironManProperties.family = {// ironMan: 'Tony Stark',// hera: 'Pepper Potts'// }// Output ironManProperties.family:ironManProperties.family; Here we assign the value of ironManCharacters.couple to the property of ironManProperties.family . Here are two points to be explained:
1. Deconstruction assignment must be included in parentheses
When we deconstruct an existing variable (such as ironManProperties in the example above), we must do this instead of declaring a new variable.
2. The pattern still matches
{ ironManCharacters: { couple... } } matches ironManCharacters in object avengers . This way, you can extract the value of ironManCharacters.couple from the avengers object as you wish. But now, a new object ironManProperties and its property family are placed behind the couple . In fact, the property ironManProperties.family of this object is actually assigned.
Are you still confused when you try to explain this situation clearly? Try the above code in jsfiddle and everything will be clear.
If you are not sure why you are doing this, please refer to the example in the next article. These examples will tell you why this pattern is used to deconstruct the JSON object called by API, allowing you to appreciate the magic of deconstruction!
default value
When deconstructing, you can also specify a default value to the variable:
// Setup our object const avengers = { ironMan: 'Tony Stark', cap: 'Steve Rogers', blackWidow: 'Natasha Romanoff' }; // Destructure using defaults const { ironMan, cap, blackWidow, theHulk='Bruce Banner' } = avengers; // ironMan = 'Tony Stark' // cap = 'Steve Rogers' // blackWidow = 'Natasha Romanoff' // theHulk = 'Bruce Banner' // Output blackWidow: blackWidow;Avoid these problems during deconstruction
Const, let, var is not used when deconstructing the assignment
This point has been mentioned when talking about deconstructing and assigning object properties, but it is still necessary to reiterate it here to give everyone a deep impression.
Cannot deconstruct declared variables
That is, you can only declare variables while deconstructing the variables.
// Setup our object const avengers = { ironMan: 'Tony Stark', cap: 'Steve Rogers', blackWidow: 'Natasha Romanoff', theHulk: 'Bruce Banner' }; // Valid destructuring const { ironMan } = avengers; let { cap } = avengers; var { blackWidow } = avengers; // Invalid destructuring let theHulk; { theHulk } = avengers; // Error // Output theHulk: theHulk;Why can't a declared variable be deconstructed? That's because if you use curly braces { then JavaScript will think you are declaring a block .
The solution is to enclose the entire deconstructed assignment in a pair of brackets .
How to deconstruct and assign a declared variable
// Setup our object const avengers = { ironMan: 'Tony Stark', cap: 'Steve Rogers', blackWidow: 'Natasha Romanoff', theHulk: 'Bruce Banner' }; // A valid Hulk let theHulk; ({ theHulk } = avengers); // theHulk = 'Bruce Banner' // Output theHulk: theHulk;Now we don't start with curly braces, so JS won't think we're declaring a block so that we can achieve the expected deconstruction result.
Returns a deconstructed value directly
When a variable to be returned next is not declared first, a deconstructed value is directly returned, which will not achieve the expected effect. For example, in the following code, the returned entire ironMan object will not be the expected value of Tony Stark .
// Note: this doesn't work! function getTonyStark(avengers){ return { ironMan: { realName } } = avengers; // return the avengers object, not the realName value } const avengers = { ironMan: { realName: 'Tony Stark' } }; const tonyStark = getTonyStark(avengers); // tonyStark = { // ironMan: { // realName: 'Tony Stark' // } // }; // Output tonyStark: tonyStark;To extract a value from a deconstructed object, you must first assign it to a variable, and then return this variable, as shown in the following code:
// Note: this DOES work! function getTonyStark(avengers){ const { ironMan: { realName } } = avengers; return realName; } const avengers = { ironMan: { realName: 'Tony Stark' } }; const tonyStark = getTonyStark(avengers); // tonyStark = 'Tony Stark' // Output tonyStark: tonyStark;This way of dividing assignment and return into two lines of code is really annoying, and the code is ugly and unnecessary. Unfortunately, JavaScript works like this - you have to assign the deconstructed value to a variable first, and then return it, and the two steps must be done separately.
However, we did not say that we just did it separately, and did not say that we must put it into two lines of code. So writing it into one line like the following can also achieve the expected results:
function getTonyStark(avengers){ return ({ ironMan: { realName } } = avengers) && realName; } const avengers = { ironMan: { realName: 'Tony Stark' } }; const tonyStark = getTonyStark(avengers); // tonyStark = 'Tony Stark' // Output tonyStark: tonyStark; Since JavaScript's _short-circuit_ circuit_logical operator (&& and ||) returns the value of the second operand based on the value of the first operand, this writing method can achieve the expected effect. Here, the first operand is to deconstruct the assignment expression and assign the value to realName . realName is the second operand, so its value is finally returned.
This is not optimal, but can be achieved. While pursuing the shortness of the code, you must pay attention to the readability of the code.
Summarize
This article explains in-depth the main principles of deconstructing assignment. Deconstruction not only reduces the amount of your code, but also fundamentally changes how you encode it. The more you use it, the more ways you can shape data and functions, which were almost impossible in the past. I hope this article will be helpful to everyone to learn ES6.