Nested deconstruction
If the value you are deconstructing has nested objects or arrays, you can also deconstruct those nested values:
Var a1 = [1, 2 and 4), 5); var o1 = { x:{y:{z:6}} }; var [ a,[b,c,d],e ] = a1; var { x:{ y :{ z:w}} } = o1; The console. The log (a, b, c, d, e) / / 1, 2, 3, 4, 5 console. The log (w) / / 6Copy the code
Nested destructuring can be a simple way to flatten object namespaces, for example:
var app = { model:{ User:function(){... }}}Copy the code
/ / replace:
// var User = App.model.User;
var { model :{ User } } = App;
Copy the code
Parameters of deconstruction
Can you find an assignment in the code below?
function foo(x) {
console.log( x );
}
foo( 42 );
Copy the code
The assignment is somewhat hidden: when foo(42) is executed, 42 times the value is assigned to x. If argument/parameter value is an assignment, then it is an assignment that can be deconstructed by convention.
Consider array deconstruction of arguments:
function foo( [x,y] ){
console.log(x,y)
}
foo( [ 1, 2] )/
/ 1 2
foo( [ 1] );
// 1 undefined
foo( [ ] )
// undefined undefined
Copy the code
Parameters can also be object destructed:
function foo ( { x , y } ){
console.log( x,y )
}
foo( { y:1,x:2 } );
// 2 1
foo( { y: 42 } )
//undefined 42
foo( {} )
// undefined undefined
Copy the code
This technique is an approximate solution to explicit parameter values (a long-desired JS feature) : attributes on an object are mapped to a deconstructed parameter of the same name. This also means that we get optional arguments for free (anywhere), and as you can see, the omitted argument x works as expected.
Of course, all the types of deconstruction discussed earlier are available for parametric deconstruction, including nested deconstruction, default values, and others. Deconstruction also blends well with other ES6 function parameter functions, such as default parameter values and residual/collection parameters. Example:
function f1([ x= 2,y=3,z ]){... } function f2([ x,y,...z ],w){... } function f3([ x,y,...z ],... w){... } function f4( { x:X ,y} ){... } function f5( { x:X=10,y=20} ){... } function f6( { x = 10 } = {},{ y } ){... }Copy the code
Let’s take an example from this code snippet:
function f3([ x,y,...z ],... W) {the console. The log (x, y, z, w)} f3 ([]) / / undefined undefined [] [] f3 (56) [1, 2, 3, 4], / / 1 2 [3, 4] [5, 6]Copy the code
There are two… Operators, which collect values into arrays (z and w), although… Z is collected from the remainder of the first array parameter value, and… W is collected from the remaining primary parameter values after the first one.
Destruct default + parameter default
There is one subtle area where you should be particularly careful – the difference between the behavior of deconstructing default values and function argument defaults. Such as:
function fn6( { x = 10 } = {} , { y } = {} ){
console.log(x,y)
}
fo( {},{} )
// 10 undefined
Copy the code
Why is that? If no property of the same name is passed in the object of the first parameter value, the named parameter x defaults to 10. But why is y undefined? The value {y:10} is an object that serves as a default value for function arguments, not a structural default. Therefore, it only takes effect if the second argument is not passed at all or if undefined is passed
In the previous code, we passed the second argument ({}), so the default {y:10} is not used, and deconstruction {y} occurs for the empty object {} that is passed in.
Now, compare {y} = {y:10} with {x =10} = {}.
For the use of x, if the first function argument value is omitted or undefined, the null object {} is used by default. Then, whatever value is in the position of the first argument value — either the default {} or the one you pass in — is deconstructed by {x=10}, which checks if the attribute x is found, and if not or undefined, the default value 10 is set to the named parameter x.
function fn6( { x = 10 } = {} , { y } = { y:10 } ){
console.log(x,y)
}
fn6()// 10 10
fn6(undefined,undefined)
// 10 10f
n6({},{})
// 10 undefined
fn6({x:2},{y:3})
// 2 3
Copy the code
In general, the default behavior of parameter x may seem preferable and more reasonable than the default behavior of parameter y. Therefore, it is important to understand why and how the {x = 10} = {} form differs from the {y} = {y = 10} form. If this is still a bit vague, go back and read it again and play with it yourself.
Nested defaults: Deconstruction and refactoring
While it may be difficult to master at first, setting default values for properties of a nested object leads to an interesting idiom: object deconstruction with something I call refactoring. Consider a set of default values in a nested object structure, like the following:
var defaults = {
options:{
remove :true,
enable:false,
instance:{}
},
log:{
warn:true,
error:true
}
};
Copy the code
Now, let’s say you have an object called config that has some of these values, but maybe not all of them, and you want to set all of the default values to the missing points of this object, but not override specific Settings that already exist:
var config = {
options:{
remove:false,
instancs:null
}
}
Copy the code
Some people might like to do this by overwriting assignments. You might be tempted by ES6’s Object.assign tool, which clones properties in defaults and overwrites them with properties cloned from Config. Assign is a shallow copy, which means that when it copies defaults.options, it only copies references to the Object, rather than deeply cloning the Object’s properties into a config.options Object. Object.assign needs to be implemented at each level of your Object tree to get the deep clone you want. Let’s see if ES6’s object deconstruction with default values can help us:
config.options = config.options || {}
config.log = config.log || {}
({
options :{
remove:config.options.remove = defaults.options.remove,
enable:config.options.enable = defaults.options.enable,
instance = config.options.instance = defaults.options.instance
} = {},
log:{
warn:config.log.warn = defaults.log.warn
error:config.log.error = defaults.log.error
} = {}
} = config )
Copy the code
Unlike the Object. The assign (…). The false promise (because it’s a shallow copy) is that good, but I think it’s much better than the manual method. Although it is still unfortunately redundant and repetitive.
The way the previous code snippet works, because I hacked into the structure and default mechanism to do the ===undefined check and assignment decisions for my property. The trick here is. I deconstructed config (look at the end = config), but I immediately assigned all the deconstructed values back to config, with the config.options.enable assignment reference, but there were still too many, The following technique works best when you know that the names of all the properties you are deconstructing are unique. But even if that’s not the case you can still use it, just not as well — you’ll have to deconstruct it in stages, or create unique local variables as temporary aliases.
If we completely deconstructed all the attributes into top-level variables, we could immediately refactor to reassemble the original nested object deconstruction, but all those temporary variables hanging out would pollute the scope. So we use block scope with a normal {} enclosing block.
{ let { options:{ remove = defaults.options.remove, enable = defaults.options.enable, instance = defaults.options.instance } = {}, log:{ warn=defaults.log.warn, error=defaults.log.error } = {} } = config; Config = {options:{remove,enable,instance}, log:{warn,error}}}Copy the code
It looks so much better!
I hope this article will help you! This article is partially excerpted from ** JS you don’t understand **!