{"id":17162113,"url":"https://github.com/thysultan/proposal-private-methods-and-fields","last_synced_at":"2025-04-10T18:10:29.821Z","repository":{"id":93021992,"uuid":"127851713","full_name":"thysultan/proposal-private-methods-and-fields","owner":"thysultan","description":null,"archived":false,"fork":false,"pushed_at":"2018-04-19T00:43:58.000Z","size":8,"stargazers_count":7,"open_issues_count":0,"forks_count":0,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-04-13T21:53:21.222Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thysultan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2018-04-03T04:40:57.000Z","updated_at":"2021-12-03T15:45:09.000Z","dependencies_parsed_at":null,"dependency_job_id":"c5267b0c-1c16-41c3-90f2-6251948186cd","html_url":"https://github.com/thysultan/proposal-private-methods-and-fields","commit_stats":{"total_commits":8,"total_committers":1,"mean_commits":8.0,"dds":0.0,"last_synced_commit":"2e7823416c80f1bad679621eebd813c0b19a3179"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thysultan%2Fproposal-private-methods-and-fields","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thysultan%2Fproposal-private-methods-and-fields/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thysultan%2Fproposal-private-methods-and-fields/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thysultan%2Fproposal-private-methods-and-fields/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thysultan","download_url":"https://codeload.github.com/thysultan/proposal-private-methods-and-fields/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248154995,"owners_count":21056542,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-14T22:44:45.115Z","updated_at":"2025-04-10T18:10:29.803Z","avatar_url":"https://github.com/thysultan.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Private methods and fields for JavaScript.\n\nStage 0\n\nChampion Needed\n\nThe following proposes a vision for private fields that conforms to the harmony of JavaScripts current syntax synergy.\n\n## Why\n\nConsider the following class.\n\n```js\nclass A {\n  constructor() {\n    this.id = Symbol('unique')\n  }\n  equal(instance, property) {\n    return this[property] == instance[property]\n  }\n}\n\nconst x = new A()\n\nx.equal(x, 'id')\n```\n\nBoth active proposals that make use of the [.#](https://github.com/tc39/proposal-class-fields) and [-\u003e](https://github.com/zenparsing/js-classes-1.1) sigils suffer from the same inability to implement this design pattern.\n\nFor example given the [.#](https://github.com/tc39/proposal-class-fields) sigil, we might try to implement it in the following way, but the lack of computed access prevents us from achieving this goal.\n\n```js\nclass A {\n  constructor() {\n    this.#id = Symbol('unique')\n  }\n  get(instance, property) {\n    // how do I get the computed private properties of another instance of A?\n    return this.#id == instance.#id\n  }\n}\n\nconst x = new A()\n\nx.equal(x, 'id')\n```\n\nThe same problem affects the [-\u003e](https://github.com/zenparsing/js-classes-1.1) sigil.\n\n```js\nclass A {\n  constructor() {\n    this-\u003eid = Symbol('unique')\n  }\n  get(instance, property) {\n    // same problem, how do I get the computed private properties of another instance of X?\n    return this-\u003eid == instance-\u003eid\n  }\n}\n\nconst x = new A()\n\nx.equal(x, 'id')\n```\n\n## What\n\nThis proposal aims to achieve these requirements without introducing an asymmetrical new syntax for private fields.\n\nThe afor-mentioned affected pattern would be implemented in following:\n\n```js\nclass A {\n  private id = Symbol('unique')\n  equal(instance, property) {\n    return private(this)[property] == private(instance)[property]\n  }\n}\n\nconst x = new A()\n\nx.equal(x, 'id')\n```\n\nThis introduces the use of the reserved keyword `private` that acts symmetrical to the use of `super` or `import` where it is both a syntax i.e `private[property]` and function `private(this)[property]`.\n\nThis means that `private(this)[property]` is equivalent to `private[property]`.\n\nThe following examples demonstrates how this might look and work with other active/future proposals.\n\n```js\nclass A {\n  // uses the private keyword to create private fields, methods, getters etc.\n  private value = 'string'\n  private method () {}\n\n  // uses the static keyword to create static fields, methods, getters etc\n  static value = 'string'\n  static method () {}\n\n  // uses neiher to create instance fields, methods, getters etc\n  value = 'string'\n  method () {}\n\n  constructor() {\n    // invoke instance method\n    this['method'](this.value)\n\n    // use private.name or private['name'] to access private fields, methods, getters etc.\n    private['method'](private['value'])\n\n    // all of the following invocations are equivalent to the previous\n    private.method(private.value)\n    private(this)['method'](private(this)['value'])\n    private(this).method(private(this).value)\n\n    // assign private values\n    private.length = 1\n    private['length'] = 1\n\n    // future facing\n    static['method'](static['value'])\n    static.method(static.value)\n  }\n}\n```\n\n## FAQ\n\n\u003eWhat does private(this)[property] do?\n\n\"private(this)[property]\" and alternatively \"private[property]\" or \"private.property\" all invoke access of a private \"property\" on the instance of the class, symmetrical to the syntax/function nature of both the \"super\" and \"import\" keywords.\n\n\u003eWhat's private about private fields?\n\nOutside of a private fields provider class, private fields/methods would not be accessible.\n\n\u003eHow do you prevent them from being forged or stuck onto unrelated objects?\n\nGiven the following:\n\n```js\nclass A {\n  private id = 0\n  private method(value) {\n    return value\n  }\n  write(value) {\n    private(this)[\"id\"] = private[\"method\"](value)\n  }\n}\n```\n\nand then invoking the above write method with a `this` value that is not an instance of `A`, for example `(new A()).write.call({}, 'pawned');`, would fail – the private syntax call site is scoped to the surrounding provider class. For example imagine the current possible transpilation of this using WeakMaps:\n\n```js\n(function (){\n  var registry = WeakMap()\n\n  function A () {\n    registry.set(this, {id: 0})\n  }\n  A.prototype.write: function () {\n    registry.get(this)[\"id\"] = registry.get(this.constructor)[\"method\"].call(this, value)\n  }\n\n  // shared(i.e private methods)\n  registry.set(A, {\n    method: function (value) {\n      return value\n    }\n  })\n\n  return A\n})()\n```\n\nTrying to do the the afore-mentioned forge here would currently fail along the lines of cannot read property `id` of  `undefined`.\n\n\u003e An instance has a fixed set of private fields which get created at object creation time.\n\nThe implications of this alternative do not limit the creation of private fields to creation time, for example writing to a private field in the constructor or at any arbitrary time within the lifecycle of the instance.\n\n```js\nclass HashTable {\n  constructor() {\n    private[Symbol.for('length')] = 0\n  }\n  set(key, value) {\n    private[key] = value\n  }\n  get(key) {\n    return private[key]\n  }\n}\n```\n\n\u003eThat would contradict your previous answer to the hijacking question. In the transpilation you created the field using \"registry.set(this, {id: 0})\", in the constructor.  If you then claim that any write to the field can also create it, then you get the hijacking behavior which you wrote doesn't happen.\n\nThe difference between the following\n\n```js\nclass A {\n  private id = 0\n}\n```\n\nand the following\n\n```js\nclass A {\n  constructor() {\n    private.id = 0\n  }\n}\n```\n\nis similar to the difference between\n\n```js\n(function (){\n  var registry = WeakMap()\n\n  function A () {\n    registry.set(this, {id: 0})\n  }\n\n  return A\n})()\n```\n\nand\n\n```js\n(function () {\n  var registry = WeakMap()\n\n  function A () {\n    registry.set(this, {})\n    registry.get(this)[\"id\"] = 0\n  }\n\n  return A\n})\n```\n\nThis in no way permits the hijacking behavior previously mentioned – `(new A()).write.call({}, 'pawned')`\n\n\u003eDo you limit classes to creating only the private fields declared in the class, or can they create arbitrarily named ones?\n\nJust as you could write to arbitrary named fields with the mentioned WeakMap approach, you can also do the same for this alternative, for example –\n\n```js\nprivate[key] = value\n// or\nprivate(this)[key] = value\n```\n\n\u003eWhat does static['method'] and static.method refer to?\n\nThis hints to a future facing proposal for static fields/methods that can share the same syntax symmetry of the proposed private fields/methods.\n\n## Related\n\n- [Yet another approach to a more JS-like syntax](https://github.com/tc39/proposal-private-methods/issues/28)\n- [Private and Protected are like Static and Super](https://github.com/tc39/proposal-class-fields/issues/90)\n- [Proposal About Private Symbols](https://esdiscuss.org/topic/proposal-about-private-symbol)\n- [Related Esdiscuss Thread](https://esdiscuss.org/topic/ecmascript-proposal-private-methods-and-fields-proposals)\n\n## Syntax Synergy\n\nSyntax synergy is a strong contributing factor to the introduction of this alternative and a much stronger contributing factor in the community push back against a `#sigil` direction to private fields/methods. In demonstration, the following is non-exhaustive collection documenting issues/disagreement/outlets expressed with the current `#sigil` syntax.\n\n\u003cdetails\u003e\n\n\u003csummary\u003eDetails\u003c/summary\u003e\n\n#### Github\n\n- [Why not use the \"private\" keyword, like Java or C#?](https://github.com/tc39/proposal-private-fields/issues/14)\n- [This proposal does not address the actually existing needs for private fields](https://github.com/tc39/proposal-private-methods/issues/22)\n- [Yet another approach to a more JS-like syntax](https://github.com/tc39/proposal-private-methods/issues/28)\n- [Proposal: keyword to replace `#` sigil](https://github.com/tc39/proposal-class-fields/issues/56)\n- [Please do not use \"#\"](https://github.com/tc39/proposal-class-fields/issues/77)\n- [Private and Protected are like Static and Super](https://github.com/tc39/proposal-class-fields/issues/90)\n- [New, more JS-like syntax](https://github.com/tc39/proposal-private-methods/issues/20)\n- [Stop this proposal](https://github.com/tc39/proposal-private-methods/issues/10)\n- [Why not use private keyword instead of #?](https://github.com/tc39/proposal-private-methods/issues/8)\n- [Independent private field](https://github.com/tc39/proposal-private-methods/issues/12)\n- [Syntax change suggestion](https://github.com/tc39/proposal-private-methods/issues/24)\n- [Yes, the negative reaction of #priv is worse, I think it's the worst in our history. I'll try to explain it.](https://github.com/zenparsing/js-classes-1.1/issues/26#issuecomment-374171662)\n- [Hash -\u003e Underscore](https://github.com/tc39/proposal-private-fields/issues/100)\n- [Can we just use private keyword?](https://github.com/tc39/proposal-private-fields/issues/92)\n- [Is this really needed if we need a sigil](https://github.com/tc39/proposal-private-fields/issues/61)\n- [Accessing private fields](https://github.com/tc39/proposal-private-fields/issues/50)\n- [Use `private.x` syntax for referencing private fields](https://github.com/tc39/proposal-private-fields/issues/18)\n- [Unrelated but the syntax looks really weird.](https://github.com/prettier/prettier/pull/2837#discussion_r139260878)\n- [This is by far my least favourite proposal that has advanced through tc39.](https://github.com/prettier/prettier/pull/2837#issuecomment-329939107)\n- [Why not use obj#prop instead obj.#prop](https://github.com/tc39/proposal-private-fields/issues/39)\n- [Use this#prop instead this.#prop](https://github.com/tc39/proposal-private-fields/issues/35)\n\n#### Twitter\n\n- [Not a fan of # for this, would prefer something with clearer semantics. # looks like bash comments or hashtags.](https://twitter.com/unthunk/status/913271895620857856)\n- [Agreed - I would prefer the keyword `private`.](https://twitter.com/joeattardi/status/913395181688369152)\n- [Python @ThePSF would be disappointed in JS. Definitely a feature I'd prefer not to have.](https://twitter.com/niklaskorz/status/913416022262190080)\n- [Even if the feature is interesting, I am really not a fan of the syntax](https://twitter.com/sbegaudeau/status/913388802877657088)\n- [Why dont we use a keyword instead of a semantic character?](https://twitter.com/codeaholicguy/status/913602347208601602)\n- [If this is how I would have to write private methods, then I am not going to use them.](https://twitter.com/jjb_official/status/914082976262230016)\n- [So ugly and unnecessary](https://twitter.com/mcfedr/status/915491622523228160)\n\n#### Medium\n\n- [Is it necessary to use a #hashtag? To me it seems too distracting...](https://medium.com/@marianban/is-it-necessary-to-use-a-hashtag-c575af85cab8)\n- [That honestly add noise and complexity to the language for little gain. That # suffix looks terrible.](https://medium.com/@richard_lopes/that-honestly-add-noise-and-complexity-to-the-language-for-little-gain-778ff951fcc3)\n- [How do I stop this from getting into JavaScript?](https://medium.com/@allycw/how-do-i-stop-this-from-getting-into-javascript-817813af7dc1)\n- [is the # required or is it just a casual (/horrible) convention?](https://medium.com/@charlesdeuter/is-the-required-or-is-it-just-a-casual-horrible-convention-b81b851f3be)\n\n\u003c/details\u003e\n\n---\n\nThis proposal is a best affort to afford these issues an alternative syntax without sacrificing the current syntax synergy of the JavaScript language.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthysultan%2Fproposal-private-methods-and-fields","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthysultan%2Fproposal-private-methods-and-fields","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthysultan%2Fproposal-private-methods-and-fields/lists"}