├── LICENSE └── README.md /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Andrea Simone Costa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tc39-proposal-dotstructuring 2 | ## Proposal: Object dotstructuring - dot property(ies) access + object destructuring 3 | 4 | This proposal is also known as: Pick Notation, Extended Object Destructuring, Extended Dot Notation. 5 | Inspired by Bob Myers' [proposal](https://github.com/rtm/js-pick-notation) released under MIT License. 6 | 7 | This is a proposal to allow read and write operations on multiple objects' properties (symbols included), leveraging object destructuring syntax to support renaming and defaults. The suggested syntax would enable quick objects creation from existing objects, to create subsets, and quick properties merging/replacing. 8 | 9 | ## Proposal details 10 | To access multiple properties from an object (sometimes referred to as "picking"), we simply extend dot notation by writing the object name (or an expression evaluating to an object), then a dot, then a destructuring-like construct: 11 | ```js 12 | obj.{prop1, prop2}; 13 | ``` 14 | Why we need a destructuring-like construct instead of a a destructuring construct (_ObjectAssignmentPattern_)?\ 15 | Dotstructuring symbols is a particular case because in normal destructuring we cannot extract directly some special Symbols since it would not make any sense, like the following: 16 | ```js 17 | const {[Symbol.iterator]} = []; 18 | ``` 19 | We have to rename it: 20 | ```js 21 | const {[Symbol.iterator]:foo} = []; 22 | ``` 23 | Considering that dotstructuring always involves two object, it has to be permitted __only for dotstructuring purposes__ to allow a complete selection of properties to copy.\ 24 | Specifically __"standalone" computed properties should be allowed__ to also enable dynamic dotstructuring: 25 | ```js 26 | const p = 'prop1'; 27 | obj.{[p]}; 28 | ``` 29 | 30 | ## RHS access (right-hand side) 31 | In this situation the object dotstructuring will: 32 | 1. pick chosen properties from the source 33 | 2. create a fresh new object 34 | 3. copy chosen props and their values into the just created object (shallow copy) 35 | 4. return the just created object 36 | 37 | ```js 38 | const source = {prop1: 42, prop2: 'foo', [Symbol.iterator]: .. }; 39 | 40 | const newObject = source.{prop1, [Symbol.iterator]}; 41 | newObject; // {prop1: 42, [Symbol.iterator]: .. }; 42 | 43 | source; // {prop1: 42, prop2: 'foo', [Symbol.iterator]: .. }; 44 | ``` 45 | The source object remains unaffected.\ 46 | The [[Prototype]] property is not copied.\ 47 |   48 | ### undefined properties 49 | If a not existing property is picked the corrisponding value will be undefined: 50 | ```js 51 | const source = {prop1: 42}; 52 | 53 | const newObject = source.{prop2}; 54 | newObject; // {prop2: undefined}; 55 | 56 | source; // {prop1: 42}; 57 | ``` 58 |   59 | ### default values for properties 60 | Dotstructuring syntax let us to set default value for properties like destructuring: 61 | ```js 62 | const source = {prop1: 42}; 63 | 64 | const newObject = source.{prop2 = 'foo'}; 65 | newObject; // {prop2: 'foo'}; 66 | 67 | source; // {prop1: 42}; 68 | ``` 69 |   70 | ### renaming properties 71 | Dotstructuring syntax let us to rename properties like destructuring: 72 | ```js 73 | const source = {prop1: 42}; 74 | 75 | const newObject = source.{prop1:p1}; 76 | newObject; // {p1: 42}; 77 | 78 | source; // {prop1: 42}; 79 | ``` 80 |   81 | ### extracting nested properties 82 | Dotstructuring syntax let us to extract nested properties like destructuring: 83 | ```js 84 | const source = {obj1: {prop1: 42}}; 85 | 86 | const newObject = source.{ obj1:{prop1} }; 87 | newObject; // {prop1: 42}; 88 | 89 | source; // {obj1: {prop1: 42}}; 90 | ``` 91 | ## Possible RHS access transpilation 92 | All the RHS object dotstructuring (symbols included) cases could be transpiled: 93 | ```js 94 | const source = {prop: .., [Symbol.iterator]: ..}; 95 | const newObject = source.{prop, [Symbol.iterator]}; 96 | ``` 97 | into: 98 | ```js 99 | const source = {prop: .., [Symbol.iterator]: ..}; 100 | const newObj = (function(obj){ 101 | var tmp = {}; 102 | return ({ prop: tmp.prop, [Symbol.iterator]: tmp[Symbol.iterator] } = obj, tmp); 103 | })(source); 104 | ``` 105 | ## LHS access (left-hand side) 106 | In this situation the object dotstructuring will: 107 | 1. pick chosen properties from the source 108 | 2. select corresponding properties in the __already existing__ target object 109 | 3. copy chosen props and their values into the target object (shallow copy), overwriting those already present in case of conflicts 110 | 4. return the just updated object 111 | 112 | ```js 113 | const source = {prop1: 42, prop2: 'foo'}; 114 | const target = {prop1: 'bar', prop3: 'baz'}; 115 | 116 | target.{prop1, prop2} = source; 117 | 118 | source; // {prop1: 42, prop2: 'foo'}; 119 | target; // {prop1: 42, prop2: 'foo', prop3: 'baz'}; 120 | ``` 121 | The source object remains unaffected.\ 122 | The [[Prototype]] property is never copied.\ 123 | The _target_ must be an already existing object because if a fresh new one is needed with one or more properties picked by another object, the RHS access has to be used: 124 | ```js 125 | const source = {prop1: 42, prop2: 'foo'}; 126 | const target.{prop1, prop2} = source; // ERROR: LHS dotstructuring does not provide an implicit object creation 127 | ``` 128 | on the contrary, use this: 129 | ```js 130 | const source = {prop1: 42, prop2: 'foo'}; 131 | const target = source.{prop1, prop2}; // RHS dotstructuring provides an implicit object creation 132 | ``` 133 |   134 | ### undefined properties 135 | If a not existing property is picked the corrisponding value in the target will be undefined: 136 | ```js 137 | const source = {}; 138 | const target = {}; 139 | 140 | target.{prop1} = source; 141 | 142 | source; // {} 143 | target; // {prop1:undefined} 144 | ``` 145 |   146 | If the property exists in the target but not in the source, that property in the target will become undefined: 147 | ```js 148 | const source = {}; 149 | const target = {prop1:42}; 150 | 151 | target.{prop1} = source; 152 | 153 | source; // {} 154 | target; // {prop1:undefined} 155 | ``` 156 |   157 | ### default values for properties 158 | Dotstructuring syntax let us to set default value for properties like destructuring: 159 | ```js 160 | const source = {}; 161 | const target = {}; 162 | 163 | target.{prop1 = 42} = source; 164 | 165 | source; // {} 166 | target; // {prop1:42} 167 | ``` 168 |   169 | ### renaming properties 170 | Dotstructuring syntax let us to rename properties like destructuring: 171 | ```js 172 | const source = {prop1:42}; 173 | const target = {}; 174 | 175 | target.{prop1:p1} = source; 176 | 177 | source; // {prop1:42} 178 | target; // {p1:42} 179 | ``` 180 |   181 | Renaming an existent property will not overwrite it: 182 | ```js 183 | const source = {prop1:42}; 184 | const target = {prop1:42}; 185 | 186 | target.{prop1:p1} = source; 187 | 188 | source; // {prop1:42} 189 | target; // {p1:42, prop1:42} 190 | ``` 191 |   192 | ### extracting nested properties 193 | Dotstructuring syntax let us to extract nested properties like destructuring: 194 | ```js 195 | const source = {obj1: {prop1: 42}}; 196 | const target = {}; 197 | 198 | target.{obj1:{prop1}} = source; 199 | 200 | target; // {prop1: 42}; 201 | source; // {obj1: {prop1: 42}}; 202 | ``` 203 | ### handling properties conflicts 204 | Target properties will be overwritten in case of conflicts: 205 | ```js 206 | const source = {prop1:42}; 207 | const target = {prop1:'foo'}; 208 | 209 | target.{prop1} = source; 210 | 211 | target; // {prop1: 42}; 212 | source; // {prop1: 42}; 213 | ``` 214 | ## Possible LHS access transpilation 215 | All the LHS object dotstructuring (symbols included) cases could be transpiled: 216 | ```js 217 | const source = {prop1: .., [Symbol.iterator]: ..}; 218 | const target = {prop2: ..}; 219 | 220 | target.{prop1, [Symbol.iterator]} = target; 221 | ``` 222 | into: 223 | ```js 224 | const source = {prop1: .., [Symbol.iterator]: ..}; 225 | const target = {prop2: ..}; 226 | 227 | Object.assign(target, (function(obj){ 228 | var tmp = {}; 229 | return ({ prop: tmp.prop, [Symbol.iterator]: tmp[Symbol.iterator] } = obj, tmp); 230 | })(source)); 231 | ``` 232 | ## Reasons 233 | Currently JavaScript syntax does not let us to pick one or more properties from an object to create a new one nor let us to merge only some chosen properties from an object to another. Object dotstructuring could be useful to easily create objects subsets and to merge/clone/replace chosen properties from an object to another. 234 | 235 | Bob Myers' [proposal](https://github.com/rtm/js-pick-notation) points out the following: 236 | 237 | Expressiveness and brevity for the common use cases of picking properties from objects into existing or new objects are reached by the proposal.\ 238 | Currently we have destructuring assignment, which provides a useful way to extract properties from objects. However, it is limited to assigning the values to variables. This proposal can be thought of as a natural extension to destructuring assignment, leveraging its syntax, to allow destructuring into properties of objects. It brings parity to the concept of destructuring.\ 239 | Picking properties from an object is a common use case in today's JavaScript, but currently requires approaches such as 240 | 241 | ```js 242 | const newObject = {prop1: object.prop1, prop2: object.prop2}; 243 | ``` 244 | 245 | or 246 | 247 | ```js 248 | const {prop1, prop2} = object; 249 | const newObject = {prop1, prop2}; 250 | ``` 251 | 252 | The use case for this feature can also be considered to be validated by the existence of the _\_.pick_ utilities available in several popular libraries. People in the real world also regularly wonder about the absence of native facilities for picking/destructuring from objects into objects, instead of just variables. 253 | 254 | It makes good sense to re-use the current dot notation, which programmers have used and loved for two decades. since what we are trying to do is in fact setting and retrieving object properties, the difference being that we are setting or retrieving more than one at a time. 255 | 256 | In that sense, this proposal can be viewed as bringing parity to both object destructuring, and dot notation, by allowing the existing destrucuturing concept to be applied uniformly in conjunction with dot notation. 257 | --------------------------------------------------------------------------------