Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Destructuring assignment": Need better introduction to object-destructuring syntax #38224

Open
ferdnyc opened this issue Feb 19, 2025 · 2 comments
Labels
Content:JS JavaScript docs

Comments

@ferdnyc
Copy link
Contributor

ferdnyc commented Feb 19, 2025

MDN URL

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment

What specific section or headline is this issue about?

No response

What information was incorrect, unhelpful, or incomplete?

I apologize for the fact that this is a somewhat "squishy" report. IMHO, the destructuring documentation in its current form still fails to adequately present the intricacies of how object destructuring (specifically) works. Most of the information is there, but (again, IMHO) too much of it is introduced by example long before it is explained, which can be confusing to readers. If you already understand how destructuring works, the documentation is fine, but as an introduction to it for a developer who doesn't already know, it seems sub-optimally organized.

The main issues, as I see it, are...

The Syntax section is an overwhelming wall of possible forms

Especially since every form is effectively doubled. For instance, i'm not convinced it's helpful to present both of these in their entirety:

const [a, b] = array;
const [a, , b] = array;
const [a = aDefault, b] = array;
const [a, b, ...rest] = array;
const [a, , b, ...rest] = array;
const [a, b, ...{ pop, push }] = array;
const [a, b, ...[c, d]] = array;
let a, b, a1, b1, c, d, rest, pop, push;
[a, b] = array;
[a, , b] = array;
[a = aDefault, b] = array;
[a, b, ...rest] = array;
[a, , b, ...rest] = array;
[a, b, ...{ pop, push }] = array;
[a, b, ...[c, d]] = array;

A similar redundant pair is presented for object-destructuring syntax.

The object-destructuring examples makes logical leaps that may not be as obvious as they're assumed to be

For instance, in this example:

const obj = { a: 1, b: { c: 2 } };
const {
  a,
  b: { c: d },
} = obj;
// Two variables are bound: `a` and `d`

...it's never even explicitly mentioned that a will have the value 1 and d will have the value 2, much less how property names and values are mapped to variable names in object-destructuring syntax.

Assigning to new variable names is only explained much, MUCH farther down the page

Eventually, the docs do cover that...

A property can be unpacked from an object and assigned to a variable with a different name than the object property.

But even that seems out of left field, because it's NEVER ONCE mentioned that object-destructuring by default creates variables with the same name as the object property! (And the early example involving a and d (above) already demonstrated the "assigning to a different variable name" case, just without providing any explanation for what was going on.)

What did you expect to see?

I think it would benefit readers, particularly less experienced ones, to present more detailed explanations, earlier in the documentation, of the process by which object destructuring maps variable names. In other words, explanations that take the reader through these equivalencies:

// These two statements are exactly equivalent methods to 
// define the const variables a=1 and b=2.
// The first is merely a shorthand for the second.
const {a, b} = {a: 1, b: 2}
const {a: a, b: b} = {a: 1, b: 2}


// These two are similarly equivalent (both define e=1, g=2)
const {e, f: {g}} = {e: 1, f: {g: 2}}
const {e: e, f: {g: g}} = {e: 1, f: {g: 2}}

// These, OTOH, both define e=1, f={g: 2}
const {e, f} = {e: 1, f: {g: 2}}
const {e: e, f: f} = {e: 1, f: {g: 2}}


// These are also exactly equivalent
const [x, y, z] = [1, 2, 3]
const {0: x, 1: y, 2: z} = [1, 2, 3]

Do you have any supporting links, references, or citations?

No response

Do you have anything more you want to share?

No response

MDN metadata

Page report details
@ferdnyc ferdnyc added the needs triage Triage needed by staff and/or partners. Automatically applied when an issue is opened. label Feb 19, 2025
@github-actions github-actions bot added the Content:JS JavaScript docs label Feb 19, 2025
@Josh-Cena
Copy link
Member

The Syntax section is an unfortunate situation. It is impossible to make it better, without deviating from our dogma that "Syntax has to present all possible valid combinations of source constructs, but without using BNF". I'm not convinced that they are bad—if you don't understand them you can ignore them and read on. There are examples with every description anyway.

The object-destructuring examples makes logical leaps that may not be as obvious as they're assumed to be

You've already read past the intro. The code you are quoting demonstrates one specific thing: the difference between a binding pattern and an assignment pattern. What values the variables have is irrelevant; only that new variables are created is. The very first section under "Description" already tells you what values they have:

const obj = { a: 1, b: 2 };
const { a, b } = obj;
// is equivalent to:
// const a = obj.a;
// const b = obj.b;

You should be able to that they are 1 and 2 respectively, and gives you the underlying mental model for how to desugar them.

Renaming is a much much rarer usage than destructuring in general. And it is my opinion (and many others') that you should not destruct if you need to rename. Furthermore, the description is general: it purposedly does not talk about anything specific to object or array patterns. Anything that only object destructuring can do (such as renaming) or only array destructuring can do (such as invoking the iterator protocol) is deferred to the "examples" section. I think they are given the right amount of attention that they need.

Nevertheless I agree that the docs are still a bit dense, sometimes underexplaining sometimes too verbose. If you have edits you want to make, I'm happy to review a PR, but I'm not sure there's anything specifically actionable for me or for others.

@ferdnyc
Copy link
Contributor Author

ferdnyc commented Feb 19, 2025

@Josh-Cena

Thanks for responding.

The Syntax section is an unfortunate situation. It is impossible to make it better, without deviating from our dogma that "Syntax has to present all possible valid combinations of source constructs, but without using BNF". [...]

*nod* I can accept that, and I do see the value of maintaining consistency unless there's a strong imperative to deviate from it, which I don't think is the case here.

The object-destructuring examples makes logical leaps that may not be as obvious as they're assumed to be

You've already read past the intro.

I mean, yeah, but the intro consists of, in toto:

  1. This introductory statement:

    The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables.

  2. A "Try it" box that only demonstrates

    1. array destructuring assignment
    2. Spread syntax with a rest property
  3. The wall o' Syntax

  4. A "Description" section that talks about "destructuring assignment" but is really (exclusively) demonstrating the binding pattern, not the assignment pattern. Which only leads to potential confusion, when the text suddenly swerves into the next section by drawing a distinction between the two. (I realize that all uses of the binding pattern still involve an assignment statement, but I'm not the one who named the patterns.)

(Rearranging your statements a bit...)

The very first section under "Description" already tells you what values they have:

const obj = { a: 1, b: 2 };
const { a, b } = obj;
// is equivalent to:
// const a = obj.a;
// const b = obj.b;
You should be able to that they are 1 and 2 respectively, and gives you the underlying mental model for how to desugar them.

Oh, agreed, for that code. There's no real need for inference, because the last two lines explicitly give the values of the variables created. (The reader can be expected to understand that obj.a is 1 and obj.b is 2.) But the code I quoted is a significant leap forward in complexity from that first example.

The code you are quoting demonstrates one specific thing: the difference between a binding pattern and an assignment pattern. What values the variables have is irrelevant; only that new variables are created is.

Renaming is a much much rarer usage than destructuring in general. And it is my opinion (and many others') that you should not destruct if you need to rename.

Furthermore, the description is general: it purposedly does not talk about anything specific to object or array patterns. Anything that only object destructuring can do (such as renaming) or only array destructuring can do (such as invoking the iterator protocol) is deferred to the "examples" section. I think they are given the right amount of attention that they need.

See, this is where you lose me, because:

  • The code I quoted does rename.
  • You're right that it doesn't talk about it, but it still uses it, which IMHO makes it even more confusing.
  • It's still demonstrating only the binding pattern — we still haven't gotten to the section on assignment pattern.

I agree that the values of the variables are irrelevant, but I don't think what they're created to represent is irrelevant. Nor do I think it's especially obvious.

The code I quoted could be expanded like so, if we follow the style of the earlier example you quoted:

const obj = { a: 1, b: { c: 2 } };
const {
  a,
  b: { c: d },
} = obj;
// is equivalent to:
// const a = obj.a;
// const d = obj.b.c;

So there we've demonstrated another binding destructuring form, but introduced the added complexities of both inner destructuring, and renaming — without comment on either. Even explicitly spelled out like that, I can imagine a first-time reader seeing const d = obj.b.c; and going, "...Wait, WHAT?"

(In fact, explicitly spelling it out like that makes that reaction slightly more likely. But only because it's likely to sail right over their heads completely UNLESS it's spelled out.)

@Josh-Cena Josh-Cena removed the needs triage Triage needed by staff and/or partners. Automatically applied when an issue is opened. label Feb 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Content:JS JavaScript docs
Projects
None yet
Development

No branches or pull requests

2 participants