This blog contains details about DeStructuring Assignment.
The Destructuring Assignment syntax is a way to assign the values from Arrays and Structs(Complex Objects), into distinct variables.
Syntax:
[variable1, variable2, ............, variableN] = [value1, value2, ......., valueN];
({key1, key2, ............, keyN} = {key1:value1, key2:value2, ......., keyN:valueN});
Conventional way of doing it is to store the object and then retrieve it using the JSON Object API calls. However using DeStructuring, it becomes very simple, where just by writing a line of code, one can extract the relevant attributes and choose to ignore the other ones.
Note: The above defined syntax of [variable1, variable2, …………, variableN] = [value1, value2, ……., valueN] , is written for the sake of simplicity. This syntax can be as complex as possible.
For example here the LVAL i.e [variable1, variable2, …………, variableN], can be substituted with complex values like Array/Struct elements or even a complex Object.
Similarly the RVAL i.e [value1, value2, ……., valueN], can be substituted by Array/Struct elements as well as Array/Struct References or even a complex Object.
Lets get into more details and try to simulate the different scenarios through examples and see how we can write some short, concise and more powerful syntax using this feature.
- Multi-Initializer Statements with same #LVAL and #RVAL
<
cfscript
>
[a, b] = [10, 20];
writeDump(a);
writeDump(b);
</
cfscript
>
- Multi-Initializer Statements with RVAL as an Array Reference
<
cfscript
>
arr = [100, 200, 300];
[a, b, c] = arr;
writeDump(a);
writeDump(b);
writeDump(c);
</
cfscript
>
- Multi-Initializer Statements by ignoring extra RVALs
<
cfscript
>
arr = [100, 200, 300];
[firstVal, secondVal] = arr;
writeDump(firstVal);
writeDump(secondVal);
</
cfscript
- Multi-Initializer Statements to ignore some values from RVAL
<
cfscript
>
function f() {
return [1, 2, 3];
}
[firstValue, , lastValue] = f();
writeDump(firstValue);
writeDump(lastValue);
</
cfscript
>
- Multi-Initializer Statements using Rest Operator(…)
<
cfscript
>
arr = [100, 200, 300, 400, 500];
[firstVal, secondVal, ...rest] = arr;
writeDump(firstVal);
writeDump(secondVal);
writeDump(rest); //assigns [300, 400, 500] to rest
</
cfscript
>
- Complex Multi-Initializer Statements
<
cfscript
>
[foo, [[bar], baz]] = [61,[[42], 23]];
writeDump(foo);
writeDump(bar);
writeDump(baz);
</
cfscript
>
- Swapping Values
<
cfscript
>
a=1;
b=2;
[a,b]=[b,a];
writeoutput
(a)
writeoutput
(b)
writeOutput
(
"<br>"
);
</
cfscript
>
<
cfscript
>
arr = [1,2,3];
[arr[2], arr[1]] = [arr[1], arr[2]];
writedump(arr);
</
cfscript
>
Object Destructuring : Up till now, we have mostly seen the examples of ArrayInitializers as well as complex DeStructuring. DeStructuring is also supported for Structs as well as Complex Objects. Lets take some examples to simulate Object Destructuring and how we can leverage this functionality for Structs.
- Multi-Initializer Statements with same #LVAL and #RVAL
<
cfscript
>
({ a, b, c } = { a: 10, b: {CF_PREV:
"2018"
,CF_CURR:
"2020"
}, c: [21,22,34] })
writeDump(a);
writeDump(b);
writeDump(c);
</
cfscript
>
- Multi-Initializer Statements using Object Reference
<
cfscript
>
student = {
firstname:
'Glad'
,
lastname:
'Chinda'
,
country:
'Nigeria'
};
// Reassign firstname
and
lastname using destructuring
({ firstname, lastname } = student);
writeDump(firstname);
writeDump(lastname);
</
cfscript
>
- Multi-Initializer Statements with LVAL Object having default Values
<
cfscript
>
student = {
firstname:
'Glad'
,
lastname:
'Chinda'
,
country:
'Nigeria'
};
// Reassign firstname
and
lastname using destructuring
({ firstname, lastname, age =25 } = student);
writeDump(firstname);
writeDump(lastname);
writeDump(age);
</
cfscript
>
- Nested Object Destructuring: Using this one can initialize attributeValues from childObjects within ParentObject.
<
cfscript
>
person = {
name:
'John Doe'
,
age: 25,
location: {
country:
'Canada'
,
city:
'Vancouver'
,
coordinates: [49.2827, -123.1207]
}
};
({name, location: {country, city, coordinates: [lat, lng]}} = person);
writeDump(name);
writeDump(city)
writeDump(lat);
writeDump(lng);
//writeDump(coordinates);
writeDump(country);
</
cfscript
>
- Rest Operator Support in Objects Destructuring Multi-Initializer Statements
<
cfscript
>
({as, bs, ...rest} = {as: 40, bs: [111,122,133], c:23, d:{CFPREV:
"2018"
,CF_CURR:
"2020"
}, e:[21,22,34]});
writeDump(as);
writeDump(bs);
writeDump(rest);
</
cfscript
>
- Ignoring RVAL in Objects Destructuring
<
cfscript
>
({ a, , c } = { a: 10, b: {CFPREV:
"2018"
,CF_CURR:
"2020"
}, c: [21,22,34] })
writeDump(a);
writeDump(c);
</
cfscript
>
- Destructuring Support in local variables using var keyword
<
cfscript
>
function func1(){
[x, y, z] = [23, 24, 25];
var [foo, [[bar], baz]] = [61, [[42], 23]];
var [a, , , p] = [
"A"
,
"B"
,
"C"
,
"P"
];
writeDump(foo);
writeDump(bar);
writeDump(baz);
writeDump(y);
writeDump(p);
}
func1();
writeDump(x);
//writeDump(p); // Will throw an Exception
//writeDump(foo); // Will throw an Exception
//writeDump(bar); //Will throw an Exception
</
cfscript
>
<!---
Code-snippet for Complex Objects
--->
<
cfscript
>
function func(){
person = {
name:
'John Doe'
,
age: 25,
location: {
country:
'Canada'
,
city:
'Vancouver'
,
coordinates: [49.2827, -123.1207]
}
};
var {as, bs, ...rest} = {as: 40, bs: [111,122,133], c:23, d:{CFPREV:
"2018"
,CF_CURR:
"2020"
}, e:[21,22,34]};
writeDump(rest);
writeDump(bs);
writeDump(as);
}
func();
//writeDump(rest); // Variable REST is undefined.
//writeDump(bs); // Variable BS is undefined.
writeDump(person);
</
cfscript
>
- Destructuring Support using Final keyword in Global as well as Local Scope
<
cfscript
>
final {as, bs, ...rest} = {as: 40, bs: [111,122,133], c:23, d:{CFPREV:
"2018"
,CF_CURR:
"2020"
}, e:[21,22,34]};
//as = 3; //should throw Final variable REST value change exception.
//rest =
"123"
; //should throw Final variable REST value change exception.
writeDump(as);
writeDump(bs);
writeDump(rest);
</
cfscript
>
<!---
Code-snippet for final var support
--->
<
cfscript
>
function func(){
person = {
name:
'John Doe'
,
age: 25,
location: {
country:
'Canada'
,
city:
'Vancouver'
,
coordinates: [49.2827, -123.1207]
}
};
var {as, bs, ...rest} = {as: 40, bs: [111,122,133], c:23, d:{CFPREV:
"2018"
,CF_CURR:
"2020"
}, e:[21,22,34]};
final var {as1, bs1, ...rest1} = {as1: 40, bs1: [111,122,133], c:23, d:{CFPREV:
"2018"
,CF_CURR:
"2020"
}, e:[21,22,34]}
writeDump(rest);
writeDump(bs);
writeDump(as1);
//as1 = [23,24,35]; // Final variable AS1 value change exception.
writeDump(as1);
}
func();
//writeDump(rest); // Variable REST is undefined.
//writeDump(bs); // Variable REST is undefined.
writeDump(person);
</
cfscript
>
<!---
Code-snippet for Complex Array Initializers
--->
<
cfscript
>
final [ax, ay, az] = [23, 24, 25];
//final var [ax, ay, az] = [23, 24, 25]; // The local variable ax cannot be declared outside of a function.
function func1(){
final [x, y, z] = [23, 24, 25];
final var [foo, [[bar], baz]] = [61, [[42], 23]];
final var [a, , , p] = [
"A"
,
"B"
,
"C"
,
"P"
];
final var [b, c, ...rest] = [10, 20, 30, 40, 50];
//foo =234; // Should throw Final Variable foo Value Change Exception
//baz = 234; // Should throw Final Variable baz Value Change Exception
//p =3; // Should throw Final Variable p Value Change Exception
//rest = [4, 5, 6]; // Should throw Final Variable rest Value Change Exception
// x = 25; // Should throw Final Variable X Value Change Exception
writeDump(foo);
writeDump(bar);
writeDump(baz);
writeDump(y);
writeDump(p);
writeDump(rest);
}
func1();
//x=25; // Should throw Final Variable X Value Change Exception
//ax =34; // Should throw Final Variable AX Value Change Exception
writeDump(x);
//writeDump(p); // Will throw an Exception
//writeDump(foo); // Will throw an Exception
//writeDump(bar); //Will throw an Exception
//writeDump(rest); //Will throw an Exception
</
cfscript
>
- Object Destructuring static keyword support : Object Destructuring can also be leveraged in components using the static keyword. A sample code-snippet is as shown below.
========================= Sample.cfc ========================= component { static [a, , , , c] = [10, 22, 33, 44, 55]; static {as, bs, ...rest} = {as: 40, bs: [111,122,133], c:23, d:{CFPREV: "2018" ,CF_CURR: "2020" }, e:[21,22,34]}; } ========================= test.cfm ========================= < cfscript > writeDump(sample::as); writeDump(sample::rest); writeDump(sample::a); writeDump(sample::c); </ cfscript > |
myObject = ${
key1,
key2,
key3,
key4,
key5,
key6
}
<
cfscript
>
a =
'foo'
;
b = 2021;
c = {};
o = {a, b, c}
writeOutput
((o.a ===
'foo'
));
writeOutput
((o.b === 2021));
writeDump((o.c));
</
cfscript
>
<
cfscript
>
CF9 =
'Centaur'
CF10 =
'Zeus'
CF11 =
'Splendor'
CF2016 =
'Raijin'
CF2018 =
'Aether'
CF2021 =
'Project Stratus'
CFReleaseCodeNames = ${
CF9,
CF10,
CF11,
CF2016,
CF2018,
CF2021
}
writeDump(CFReleaseCodeNames);
</
cfscript
>
This is a great feature, love using it in JavaScript, but the CF implementation misses it’s most powerful implementation and that is using it with function parameters. One should be able to call a function and pass a struct of named params with destructuring notation and have the inputs mapped.
Example:
var bar = {opt1: 1, opt2: 2, opt3:3};
function foo(required numeric opt1, any …opts){
writedump(arguments);
}
foo({bar});
Expected output:
{ opt1: 1, opts: {opt2: 2, opt3: 3} }
I hope this makes sense. It is how I use this functionality in JS.
Thanks for sharing the observation. And while someone at Adobe MAY see this and respond, you would do better to file this also as a feature request at https://tracker.adobe.com . Adobe really does pay attention to that (and sometimes to here).
Also, if you do that, you may want to help those not familiar with the implementation in JS (or the feature in general) by showing a working example in JS, such as could be could run at jsfiddle.net. That could help some better connect the dots of how what you propose does indeed work in JS.
Thanks Charlie, MDN already has examples of object destructuring in function parameters in their docs. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#object_destructuring
Looks like someone made this suggestion in 2019 and they marked it as “fixed”.
Nope, I don’t work for Adobe. I do work with them, as an ACP (Adobe Community Professional), and I may evangelize (and even do apologetics) on their behalf, but nope, not an employee. As always, I’m just trying to help.
BTW, whenever I speak, I clearly indicate that I am an independent consultant, on the front slide, then later when I introduce myself after the intro to the talk, and then also on the bottom of all my slides. I’d never intend (at all) to convey or leave open the impression that I work for Adobe (or anyone, but myself).
About that MSDN page, I wonder if to meant to share another. That one does certainly discuss destructuring assignment, but I didn’t see any that showed its use in passing function arguments as you proposed. If there is another, that would be a help for many, I’m sure.
Look for ‘Unpacking fields from objects passed as a function parameter’ as a simple example.
Using spread in function calls: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#spread_in_function_calls
Interesting about the existing tracker ticket. And you added your comment asking about it being fixed there, and I offered a possible explanation. But in case people here don’t go there, let me offer it (and a bit more) here:
The info from Adobe also indicated “For2022Triage”, which is certainly interesting to see. It suggests perhaps maybe the “fix” is coming in a CF2022. I agree they could be more clear, as that’s in the “component” field rather than the update/build. Perhaps they have to do this because there is not technically yet a cf2022.
And I’d heard some other rumblings that the next CF version would be called that (or would come out this year), so we shall see, on both fronts. 🙂
Also, you offered there a link to a cffiddle example you created. I’m sharing that also for readers here, who may not have gone there. Also, about that example, it does not “fail”. You may want to revise it or clarify better what output yo unexpected it to produce.
Finally, of course, the folks there wouldn’t know about our discussions here, so I added a link there pointing to this. Such cross-posting of discussions can get messy, but I’m just trying to help given what you’ve offered.
Thanks for the additional feedback.
Ah, ok (on that “unpacking” example). I was focusing more on the rest (“…”) aspect in your first example here and didn’t see that there.
But I see now how you’d hope to be able to name a struct key as the arg of a function, and pass the function the struct and have it figure it out/unpack it. I understand now, and hopefully this example (on top of yours and Abram’s in the tracker ticket) may help Adobe see what you want and deliver that in that seemingly upcoming enhancement.
So pretty interesting and I’ll admit that some of this went over my head and made me think hard about what was going on. I’d be interested in seeing a real world example of how you would use this if you were able to put one together. This is pretty abstract and I think it’d help me grasp it more firmly seeing it in a real world scenario. That being said I think I can see how I may could use this so will start trying to play.
Also I am assuming this is CF2021 specific? On CFFiddle the code would only run with 2021 selected so may be worthy of noting in the description unless I am incorrect that is.
Thanks
Grae, yep, this is new to cf2021. And I can relate to your sentiment, having felt similarly when I first saw the feature and similar examples in the pre-release.
Fwiw, I will say that the feature is a generic one, and if you Google on it you’ll find it’s supported by other languages like Javascript, Python, etc.
And if you find resources on using the feature with those, the examples are similar, showing “how it works” but not so much “why would one bother”. I suspect they figure people can be left to connect the dots for the various ways one might leverage the capabilities.
But fwiw, as I kept looking for anything more, I did find this which you may appreciate :
https://www.smashingmagazine.com/2019/09/reintroduction-destructuring-assignment/
No, it’s not cf-specific, but again neither is the feature. Hope it may help.
You must be logged in to post a comment.