Destructuring instances with private fields

# kdex (6 years ago)

Often times, when I use a class field a lot, I create a local binding for it, so that I don't have to prefix every appearance with this.:

class Foo {
	bar = 1;
	method() {
		const { bar } = this;
		/* … */
	}
}

The same approach would currently be illegal syntax if bar is declared to be private:

class Foo {
	#bar = 1;
	method() {
		const { #bar } = this;
		/* … */
	}
}

How is the destructuring assignment supposed to behave anyway? Introduce a local bar binding, just like above?

Whatever it should do, even defining an explicit name for the binding is currently illegal:

class Foo {
	#bar = 1;
	method() {
		const { #bar: bar } = this;
		/* … */
	}
}

This feels really asymmetric to public fields and has come up in the class fields proposal[1] before, though it was suggested to defer it to a separate proposal.

Is someone currently working on said proposal?

[1] tc39/proposal-class-fields#4

# Ranando King (6 years ago)

I can understand why this would be wanted. It would save some excess typing. However, doesn't it also lead to the potential foot-gun of forgetting to assign any modifications back to the original private field? Also, since private fields aren't actually own properties of the instance, how could they possibly be destructured? There's no programmatically exposed listing of the private fields. Further, under proposal-class-fields private fields are restricted to just class instances, so the destructuring syntax doesn't make sense for that scenario. Basically it would imply that the following is true:

let bar1 = "bar", bar2;
({ #fubar: bar2}) = { #fubar: bar1 };
bar1 === bar2;

Even if proposal-class-fields allowed for private fields on objects, it wouldn't work. There's no way to reify the left side's #fubar as a private name of the object on the right side before processing the object on the right side. Put another way, without obj. in front of it, #field cannot be lexically resolved as a private name while parsing unless the parser, upon finding the object on the right side of the =, re-evaluates the left side. Since destructuring can be arbitrarily complex, this becomes a mess very nearly as complex as trying to accurately deep clone an arbitrary object.

# Isiah Meadows (6 years ago)

BTW, this just falls out of the grid with my private symbols suggestion.... tc39/proposal-class-fields#115

# Ranando King (6 years ago)

I can make it work work under my proposal-object-members by making '#' a postfix unary operator, but then it would have to be a syntax error to use it that way unless we're dealing with a destructuring operation. That just opens up too many ways to abuse it and leak the private container. So that's a no-go as well.