{"id":13670216,"url":"https://github.com/tc39/proposal-logical-assignment","last_synced_at":"2025-04-27T09:32:00.214Z","repository":{"id":66034267,"uuid":"121713141","full_name":"tc39/proposal-logical-assignment","owner":"tc39","description":"A proposal to combine Logical Operators and Assignment Expressions","archived":true,"fork":false,"pushed_at":"2020-07-21T20:36:57.000Z","size":217,"stargazers_count":300,"open_issues_count":4,"forks_count":13,"subscribers_count":60,"default_branch":"master","last_synced_at":"2024-08-03T09:07:12.090Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://tc39.es/proposal-logical-assignment/","language":"HTML","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/tc39.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-02-16T04:00:35.000Z","updated_at":"2024-07-12T23:58:55.000Z","dependencies_parsed_at":"2023-03-21T01:17:42.462Z","dependency_job_id":null,"html_url":"https://github.com/tc39/proposal-logical-assignment","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tc39%2Fproposal-logical-assignment","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tc39%2Fproposal-logical-assignment/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tc39%2Fproposal-logical-assignment/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tc39%2Fproposal-logical-assignment/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tc39","download_url":"https://codeload.github.com/tc39/proposal-logical-assignment/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224067039,"owners_count":17250102,"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-08-02T09:00:36.253Z","updated_at":"2024-11-11T07:31:16.156Z","avatar_url":"https://github.com/tc39.png","language":"HTML","funding_links":[],"categories":["HTML"],"sub_categories":[],"readme":"# proposal-logical-assignment\n\nA proposal to combine Logical Operators and Assignment Expressions:\n\n```js\n// \"Or Or Equals\" (or, the Mallet operator :wink:)\na ||= b;\na || (a = b);\n\n// \"And And Equals\"\na \u0026\u0026= b;\na \u0026\u0026 (a = b);\n\n// \"QQ Equals\"\na ??= b;\na ?? (a = b);\n```\n\n## Status\n\nCurrent [Stage](https://tc39.es/process-document/): 4\n\n## Champions\n\n- Justin Ridgewell ([@jridgewell](https://github.com/jridgewell/))\n- Hemanth HM ([@hemanth](https://github.com/hemanth/))\n\n## Motivation\n\nConvenience operators, inspired by\n[Ruby's](https://docs.ruby-lang.org/en/2.5.0/syntax/assignment_rdoc.html#label-Abbreviated+Assignment).\nWe already have a dozen [mathematical assignment\noperators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators),\nbut we don't have ones for the often used logical operators.\n\n```js\nfunction example(a) {\n  // Default `a` to \"foo\"\n  if (!a) {\n    a = 'foo';\n  }\n}\n```\n\nIf statements work, but terseness would be nice. Especially when dealing\nwith deep property assignment:\n\n```js\nfunction example(opts) {\n  // Ok, but could trigger setter.\n  opts.foo = opts.foo ?? 'bar'\n\n  // No setter, but 'feels wrong' to write.\n  opts.baz ?? (opts.baz = 'qux');\n}\n\nexample({ foo: 'foo' })\n```\n\nWith this proposal, we get terseness and we don't have to suffer from\nsetter calls:\n\n```js\nfunction example(opts) {\n  // Setters are not needlessly called.\n  opts.foo ??= 'bar'\n\n  // No repetition of `opts.baz`.\n  opts.baz ??= 'qux';\n}\n\nexample({ foo: 'foo' })\n```\n\n## Semantics\n\nThe logical assignment operators function a bit differently than their\nmathematical assignment friends. While math assignment operators\n_always_ trigger a set operation, logical assignment embraces their\nshort-circuiting semantics to avoid it when possible.\n\n```js\nlet x = 0;\nconst obj = {\n  get x() {\n    return x;\n  },\n  \n  set x(value) {\n    console.log('setter called');\n    x = value;\n  }\n};\n\n// This always logs \"setter called\"\nobj.x += 1;\nassert.equal(obj.x, 1);\n\n// Logical operators do not call setters unnecessarily\n// This will not log.\nobj.x ||= 2;\nassert.equal(obj.x, 1);\n\n// But setters are called if the operator does not short circuit\n// \"setter called\"\nobj.x \u0026\u0026= 3;\nassert.equal(obj.x, 3);\n```\n\nIn most cases, the fact that the set operation is short-circuited has no\nobservable impact beyond performance. But when it has side effects, it\nis often desirable to avoid it when appropriate. In the following\nexample, if the `.innerHTML` setter was triggered uselessly, it could\nresult in the loss of state (such as focus) that is not serialized in\nHTML:\n\n```js\ndocument.getElementById('previewZone').innerHTML ||= '\u003ci\u003eNothing to preview\u003c/i\u003e';\n```\n\nSee discussion of short-circuit semantics in [#3](https://github.com/tc39/proposal-logical-assignment/issues/3). It also highlights differences already present in mathematical assignment operators in code like `obj.deep[key++] += 1` vs `obj.deep[key] = obj.deep[key++] + 1`.\n\n## Related\n\n- [Ruby's logical operators](https://docs.ruby-lang.org/en/2.5.0/syntax/assignment_rdoc.html#label-Abbreviated+Assignment)\n  - [Explainer on no-set semantics](http://www.rubyinside.com/what-rubys-double-pipe-or-equals-really-does-5488.html)\n- [CoffeeScript](http://coffeescript.org/#try:a%20%3D%201%0Ab%20%3D%202%0A%0A%0A%23%20%22Or%20Or%20Equals%22%20(or%2C%20the%20Mallet%20operator%20%3Awink%3A)%0Aa%20%7C%7C%3D%20b%3B%0Aa%20%7C%7C%20(a%20%3D%20b)%3B%0A%0A%23%20%22And%20And%20Equals%22%0Aa%20%26%26%3D%20b%3B%0Aa%20%26%26%20(a%20%3D%20b)%3B%0A%0A%23%20Eventually....%0A%23%20%22QQ%20Equals%22%0A%23a%20%3F%3F%3D%20b%3B%0A%23a%20%3F%3F%20(a%20%3D%20b)%3B%0A)\n- [C#'s null coalescing assignment](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/null-coalescing-assignment#detailed-design)\n- My very first [Babel PR](https://github.com/babel/babel/pull/516) (back when it was still [6to5](https://github.com/babel/babel/tree/ecd85f53b4764ada862537aa767699814f1f1fe2)). 😄\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftc39%2Fproposal-logical-assignment","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftc39%2Fproposal-logical-assignment","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftc39%2Fproposal-logical-assignment/lists"}