keithamus / proposal-object-freeze-seal-syntax

A JavaScript TC39 proposal for Object.freeze & Object.seal syntax
https://www.keithcirkel.co.uk/object-freeze-seal-syntax
59 stars 8 forks source link

Confusion between privacy, frozen, const and extraneous properties #28

Open DominoPivot opened 2 years ago

DominoPivot commented 2 years ago

This proposal adds sugar syntax that serves three very different purposes:

I believe that using the same syntax for these different purposes is likely to cause confusion, even more so when the symbol # is already used to mark private class fields. In fact, the way this proposal is phrased seems to already confuse the meaning of frozen objects and constants.

Create immutable objects

// proposed syntax
let p1 = {# x: 0, y: 0 #};
p1.x = 5; // TypeError in strict mode

// current alternative
let p2 = Object.freeze(Object.setPrototypeOf({ x: 0, y: 0 }, null));
p2.x = 5; // TypeError in strict mode

Note that I used Object.setPrototypeOf instead of a combination of Object.create(null) and Object.assign because the latter does not preserve getter properties.

While I would like to see some sugar syntax added to JavaScript for this, I don't think the use of {# ... #} for this is intuitive or legible, especially when used inside a class with private fields:

get position() {
    return {# x: this.#x, y: this.#y #};
}

Destructure arguments into constants

// proposed syntax
function horiz({# x, y #}) {
    y = 0; // TypeError
    return {x, y};
}

// current alternative
function horiz(point) {
    const {x, y} = point;
    y = 0; // TypeError;
    return {x, y};
}

I don't think we need new syntax for this, but if we did, it should arguably use the const keyword.

This proposed syntax not only introduces a new way to create constants, but also makes destructuring in function arguments work differently than in an assignment:

let numbers = { odd: [1, 3, 5], even: [0, 2, 4] };
let {# odd, even #} = numbers;  // is this allowed? what does it do?

Forbid extra properties on destructured object

function ajax({| url, headers, onSuccess |}) {
  fetch(url, { headers }).then(onSuccess)
}

ajax({ url: "http://example.com", onsuccess: console.log });
// throws TypeError("cannot define property `onsuccess`. Object is not extensible")

The error message "Object is not extensible" is incorrect. The object passed to the function is very much extensible. This feature seems out of place in this proposal, as it has nothing to do with freezing/sealing objects.

This syntax also does not provide a mean to forbid extraneous positional arguments.