├── .gitattributes ├── .gitignore ├── .npmrc ├── LICENSE ├── README.md ├── index.html ├── package.json └── spec.emu /.gitattributes: -------------------------------------------------------------------------------- 1 | index.html -diff merge=ours 2 | spec.js -diff merge=ours 3 | spec.css -diff merge=ours 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | # Only apps should have lockfiles 40 | yarn.lock 41 | package-lock.json 42 | npm-shrinkwrap.json 43 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 ECMA TC39 and contributors 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 | # Slice notation 2 | 3 | This repository contains a proposal for adding slice notation syntax 4 | to JavaScript. This is currently at stage 1 of the [TC39 5 | process](https://tc39.github.io/process-document/). 6 | 7 | Champions: 8 | 9 | - Sathya Gunasekaran (@gsathya) 10 | - HE Shi-Jun (@hax) 11 | 12 | 13 | ## Introduction 14 | 15 | The slice notation provides an ergonomic alternative to the various 16 | slice methods present on Array.prototype, TypedArray.prototype, etc. 17 | 18 | ```js 19 | const arr = ['a', 'b', 'c', 'd']; 20 | 21 | arr[1:3]; 22 | // → ['b', 'c'] 23 | 24 | arr.slice(1, 3); 25 | // → ['b', 'c'] 26 | ``` 27 | 28 | This notation can be used for slice operations on primitives 29 | like Array and TypedArray. 30 | 31 | 32 | ## Motivation 33 | 34 | ```js 35 | const arr = ['a', 'b', 'c', 'd']; 36 | arr.slice(3); 37 | // → ['a', 'b', 'c'] or ['d'] ? 38 | ``` 39 | 40 | In the above example, it's not immediately clear if the newly created 41 | array is a slice from the range `0` to `3` or from `3` to `len(arr)`. 42 | 43 | ```js 44 | const arr = ['a', 'b', 'c', 'd']; 45 | arr.slice(1, 3); 46 | // → ['b', 'c'] or ['b', 'c', 'd'] ? 47 | ``` 48 | 49 | Adding a second argument is also ambiguous since it's not clear if the 50 | second argument specifies an upper bound or the length of the new 51 | slice. 52 | 53 | Programming language like Ruby and C++ take the length of the new 54 | slice as the second argument, but JavaScript's slice methods take the 55 | upper bound as the second argument. 56 | 57 | ```js 58 | const arr = ['a', 'b', 'c', 'd']; 59 | arr[3:]; 60 | // → ['d'] 61 | 62 | arr[1:3]; 63 | // → ['b', 'c'] 64 | ``` 65 | 66 | With the new slice syntax, it's immediately clear that the lower bound 67 | is `3` and the upper bound is `len(arr)`. It makes the intent 68 | explicit. 69 | 70 | The syntax is also much shorter and more ergonomic than a function 71 | call. 72 | 73 | ## Examples 74 | 75 | In the following text, 'length of the object' refers to the `length` 76 | property of the object. 77 | 78 | ### Default values 79 | 80 | The lower bound and upper bound are optional. 81 | 82 | The default value for the lower bound is 0. 83 | 84 | ```js 85 | const arr = ['a', 'b', 'c', 'd']; 86 | 87 | arr[:3]; 88 | // → ['a', 'b', 'c'] 89 | ``` 90 | 91 | The default value for the upper bound is the length of the object. 92 | 93 | 94 | ```js 95 | const arr = ['a', 'b', 'c', 'd']; 96 | arr[1:]; 97 | // → ['b', 'c', 'd'] 98 | ``` 99 | 100 | Omitting all lower bound and upper bound value, produces a new copy of the object. 101 | ```js 102 | const arr = ['a', 'b', 'c', 'd']; 103 | 104 | arr[:]; 105 | // → ['a', 'b', 'c', 'd'] 106 | ``` 107 | 108 | ### Negative indices 109 | 110 | If the lower bound is negative, then the start index is computed as 111 | follows: 112 | 113 | ```js 114 | start = max(lowerBound + len, 0) 115 | ``` 116 | 117 | where `len` is the length of the object. 118 | 119 | ```js 120 | const arr = ['a', 'b', 'c', 'd']; 121 | 122 | arr[-2:]; 123 | // → ['c', 'd'] 124 | ``` 125 | 126 | In the above example, `start = max((-2 + 4), 0) = max(2, 0) = 2`. 127 | 128 | ```js 129 | const arr = ['a', 'b', 'c', 'd']; 130 | 131 | arr[-10:]; 132 | // → ['a', 'b', 'c', 'd'] 133 | ``` 134 | 135 | In the above example, `start = max((-10 + 4), 0) = max(-6, 0) = 0`. 136 | 137 | Similarly, if the upper bound is negative, the end index is computed 138 | as follows: 139 | 140 | ```js 141 | end = max(upperBound + len, 0) 142 | ``` 143 | 144 | ```js 145 | const arr = ['a', 'b', 'c', 'd']; 146 | 147 | arr[:-2]; 148 | // → ['a', 'b'] 149 | 150 | arr[:-10]; 151 | // → [] 152 | ``` 153 | 154 | These semantics exactly match the behavior of existing slice 155 | operations. 156 | 157 | ### Out of bounds indices 158 | 159 | Both the lower and upper bounds are capped at the length of the object. 160 | 161 | ```js 162 | const arr = ['a', 'b', 'c', 'd']; 163 | 164 | arr[100:]; 165 | // → [] 166 | 167 | arr[:100]; 168 | // → ['a', 'b', 'c', 'd'] 169 | ``` 170 | 171 | These semantics exactly match the behavior of existing slice 172 | operations. 173 | 174 | ## Prior art 175 | 176 | ### Python 177 | 178 | This proposal is highly inspired by Python. Unsurprisingly, the 179 | Python syntax for slice notation is strikingly similar: 180 | 181 | ```python 182 | slicing ::= primary "[" slice_list "]" 183 | slice_list ::= slice_item ("," slice_item)* [","] 184 | slice_item ::= expression | proper_slice 185 | proper_slice ::= [lower_bound] ":" [upper_bound] [ ":" [stride] ] 186 | lower_bound ::= expression 187 | upper_bound ::= expression 188 | stride ::= expression 189 | ``` 190 | 191 | Examples: 192 | 193 | ```python 194 | arr = [1, 2, 3, 4]; 195 | 196 | arr[1:3]; 197 | // → [2, 3] 198 | 199 | arr[1:4:2] 200 | // → [2, 4] 201 | ``` 202 | 203 | ### CoffeeScript 204 | 205 | CoffeeScript provides a Range operator that is _inclusive_ with respect 206 | to the upper bound. 207 | 208 | ```coffeescript 209 | arr = [1, 2, 3, 4]; 210 | arr[1..3]; 211 | // → [2, 3, 4] 212 | ``` 213 | 214 | CoffeeScript also provides another form the Range operator that is _exclusive_ with respect 215 | to the upper bound. 216 | 217 | ```coffeescript 218 | arr = [1, 2, 3, 4]; 219 | arr[1...3]; 220 | // → [2, 3] 221 | ``` 222 | 223 | ### Go 224 | 225 | Go offers [slices](https://gobyexample.com/slices): 226 | 227 | ```go 228 | arr := []int{1,2,3,4}; 229 | arr[1:3] 230 | // → [2, 3] 231 | ``` 232 | 233 | There is also ability to *not* provide lower or upper bound: 234 | 235 | ```go 236 | arr := []int{1,2,3,4}; 237 | arr[1:] 238 | // → [2, 3, 4] 239 | 240 | arr := []int{1,2,3,4}; 241 | arr[:3] 242 | // → [1, 2, 3] 243 | ``` 244 | 245 | ### Ruby 246 | 247 | Ruby seems to have two different ways to get a slice: 248 | 249 | * Using a Range: 250 | 251 | ```ruby 252 | arr = [1, 2, 3, 4]; 253 | arr[1..3]; 254 | // → [2, 3, 4] 255 | ``` 256 | 257 | This is similar to CoffeeScript. The `1..3` produces a Range object 258 | which defines the set of indices to be sliced out. 259 | 260 | * Using the comma operator: 261 | 262 | ```ruby 263 | arr = [1, 2, 3, 4]; 264 | arr[1, 3]; 265 | // → [2, 3, 4] 266 | ``` 267 | 268 | The difference here is that the second argument is actually the length 269 | of the new slice, not the upper bound index. 270 | 271 | This is currently valid ECMAScript syntax which makes this a non 272 | starter. 273 | 274 | ```js 275 | const s = 'foobar' 276 | s[1, 3] 277 | // → 'b' 278 | ``` 279 | 280 | 281 | ## FAQ 282 | 283 | ### Why pick the Python syntax over the Ruby/CoffeeScript syntax? 284 | 285 | The Python syntax which excludes the upper bound index is 286 | similar to the existing slice methods in JavaScript. 287 | 288 | We could use exclusive Range operator (`...`) from CoffeeScript, but 289 | that doesn't quite work for all cases because it's ambiguous with the 290 | spread syntax. Example code from 291 | [getify](https://gist.github.com/getify/49ae9a1f2a6031d40f5deb5ea25faa62): 292 | 293 | ```js 294 | Object.defineProperty(Number.prototype,Symbol.iterator,{ 295 | *value({ start = 0, step = 1 } = {}) { 296 | var inc = this > 0 ? step : -step; 297 | for (let i = start; Math.abs(i) <= Math.abs(this); i += inc) { 298 | yield i; 299 | } 300 | }, 301 | enumerable: false, 302 | writable: true, 303 | configurable: true 304 | }); 305 | 306 | const range = [ ...8 ]; 307 | // → [0, 1, 2, 3, 4, 5, 6, 7, 8] 308 | ``` 309 | 310 | ### Why does this not use the iterator protocol? 311 | 312 | The iterator protocol isn't restricted to index lookup making it 313 | incompatible with this slice notation which works only on 314 | indices. 315 | 316 | For example, Map and Sets have iterators but we shouldn't be able to 317 | slice them as they don't have indices. 318 | 319 | ### What about splice? 320 | 321 | CoffeeScript allows similar syntax to be used on the left hand side of 322 | an `AssignmentExpression` leading to splice operation. 323 | 324 | ```coffeescript 325 | numbers = [1, 2, 3, 4] 326 | numbers[2..4] = [7, 8] 327 | // → [1, 2, 7, 8] 328 | ``` 329 | 330 | This feature is currently omitted to limit the scope of the proposal, 331 | but can be incorporated in a follow on proposal. 332 | 333 | ### Why doesn't this include a step argument like Python does? 334 | 335 | The step argument makes the slice notation ambiguous with the bind operator. 336 | 337 | ```js 338 | const x = [2]; 339 | const arr = [1, 2, 3, 4]; 340 | arr[::x[0]]; 341 | ``` 342 | 343 | Is the above creating a new array with values `[1, 3]` or is it 344 | creating a bound method? 345 | 346 | ### Should this create a `view` over the array, instead of a creating new array? 347 | 348 | Go creates a `slice` over the underlying array, instead of allocating a new array. 349 | 350 | ```go 351 | arr := []int{1,2,3,4}; 352 | v = arr[1:3]; 353 | // → [2, 3] 354 | ``` 355 | 356 | Here, v is just descriptor that holds a reference to the original 357 | array `arr`. No new array allocation is performed. See [this blog 358 | post](https://blog.golang.org/go-slices-usage-and-internals) for more 359 | details. 360 | 361 | This doesn't map to any existing construct in JavaScript and this would 362 | be a step away from how methods work in JavaScript. To make this 363 | syntax work well within the JavaScript model, such a `view` data 364 | structure is not included in this proposal. 365 | 366 | ### Should slice notation work on strings? 367 | 368 | The `String.prototype.slice` method doesn't work well with unicode 369 | characters. [This blog 370 | post](https://mathiasbynens.be/notes/javascript-unicode) by Mathias 371 | Bynens, explains the problem. 372 | 373 | Given that the existing method doesn't work well, this proposal 374 | does not add `@@slice` to `String.prototype`. 375 | 376 | ### How about combining this with `+` for append? 377 | 378 | ```js 379 | const arr = [1, 2, 3, 4] + [5, 6]; 380 | // → [1, 2, 3, 4, 5, 6] 381 | ``` 382 | 383 | This is not included in order to keep the proposal's scope maximally 384 | minimal. 385 | 386 | The [operator overloading 387 | proposal](https://github.com/keithamus/ecmascript-operator-overloading-proposal) 388 | may be a better fit for this. 389 | 390 | ### Can you create a Range object using this syntax? 391 | 392 | The slice notation only provides an ergonomic syntax for performing a slice 393 | operation. 394 | 395 | The current slice notation doesn't preclude creating a range primitive in the 396 | future. 397 | 398 | A new Range primitive is being discussed here: 399 | https://github.com/tc39/proposal-Number.range/issues/22 400 | 401 | ### Isn't it confusing that this isn't doing property lookup? 402 | 403 | This is actually doing a property lookup using `[[Get]]` on the 404 | underlying object. For example, 405 | 406 | ```js 407 | const arr = [1, 2, 3, 4]; 408 | 409 | arr[1:3]; 410 | // → [2, 3] 411 | ``` 412 | 413 | This is doing a property lookup for the keys `1` and `2`. 414 | 415 | But, shouldn't it do a lookup for the string `'1:3'`? 416 | 417 | ```js 418 | const arr = [1, 2, 3, 4]; 419 | 420 | arr['1:3']; 421 | // → undefined 422 | ``` 423 | 424 | No. The slice notation makes it analogous with how keyed lookup 425 | works. The key is first evaluated to a value and then the lookup 426 | happens using this value. 427 | 428 | ```js 429 | const arr = [1, 2, 3, 4]; 430 | const x = 0; 431 | 432 | arr[x] !== arr['x']; 433 | // → true 434 | ``` 435 | 436 | The slice notation works similarly. The notation is first evaluated to 437 | a range of values and then each of the values are looked up. 438 | 439 | ### There are already many modes where ':' mean different things. Isn't this confusing? 440 | 441 | Depending on context `a:b`, can mean: 442 | 443 | - `LabelledStatement` with `a` as the label 444 | - Property a with value b in an object literal: `{a: b }` 445 | - ConditionalExpression: `confused ? a : b` 446 | - Potential type systems (like TypeScript and Flow) that might make it 447 | to JavaScript in the future. 448 | 449 | Is it a lot of overhead to disambiguate between modes with context? 450 | Major mainstream programming languages like Python have all these 451 | modes and are being used as a primary tool for teaching programming. 452 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | Slice notation

Stage 1 Draft / June 24, 2020

Slice notation

1845 | 1846 | 1847 |

1 Well-Known Symbols

1848 |

Well-known symbols are built-in Symbol values that are explicitly referenced by algorithms of this specification. They are typically used as the keys of properties whose values serve as extension points of a specification algorithm. Unless otherwise specified, well-known symbols values are shared by all realms (8.2).

1849 |

Within this specification a well-known symbol is referred to by using a notation of the form @@name, where “name” is one of the values listed in Table 1.

1850 |
Table 1: Well-known Symbols
1851 | 1852 | 1853 | 1854 | 1857 | 1860 | 1863 | 1864 | 1865 | 1868 | 1871 | 1874 | 1875 | 1876 |
1855 | Specification Name 1856 | 1858 | [[Description]] 1859 | 1861 | Value and Purpose 1862 |
1866 | @@slice 1867 | 1869 | "Symbol.slice" 1870 | 1872 | A method that slices the receiver based on a start and end index. 1873 |
1877 |
1878 |
1879 | 1880 | 1881 |

2 Properties of the Symbol Constructor

1882 | 1883 |

2.1 Symbol.slice

1884 |

The initial value of Symbol.slice is the well known symbol @@slice (Table 1).

1885 |

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.

1886 |
1887 |
1888 | 1889 | 1890 |

3 Properties of the Array Prototype

1891 | 1892 |

3.1 Array.prototype [ @@slice ] (start, end)

1893 |

The initial value of the @@slice property is the same function object as the initial value of the Array.prototype.slice property.

1894 |
1895 |
1896 | 1897 | 1898 |

4 Properties of the %TypedArray.prototype% Object

1899 | 1900 |

4.1 %TypedArray%.prototype [ @@slice ] (start, end)

1901 |

The initial value of the @@slice property is the same function object as the initial value of the %TypedArray%.prototype.slice property.

1902 |
1903 |
1904 | 1905 | 1906 |

5 Properties of the ArrayBuffer Prototype Object

1907 | 1908 |

5.1 ArrayBuffer.prototype [ @@slice ] (start, end)

1909 |

The initial value of the @@slice property is the same function object as the initial value of the ArrayBuffer.prototype.slice property.

1910 |
1911 |
1912 | 1913 | 1914 |

6 Properties of the SharedArrayBuffer Prototype Object

1915 | 1916 |

6.1 SharedArrayBuffer.prototype [ @@slice ] (start, end)

1917 |

The initial value of the @@slice property is the same function object as the initial value of the SharedArrayBuffer.prototype.slice property.

1918 |
1919 |
1920 | 1921 | 1922 |

7 Left-Hand-Side Expressions

1923 |

Syntax

1924 | 1925 | MemberExpression[Yield, Await]:PrimaryExpression[?Yield, ?Await] 1926 | MemberExpression[?Yield, ?Await][Expression[+In, ?Yield, ?Await]] 1927 | MemberExpression[?Yield, ?Await].IdentifierName 1928 | MemberExpression[?Yield, ?Await]TemplateLiteral[?Yield, ?Await] 1929 | SuperProperty[?Yield, ?Await] 1930 | MetaProperty 1931 | newMemberExpression[?Yield, ?Await]Arguments[?Yield, ?Await] 1932 | MemberExpression[?Yield, ?Await][AssignmentExpression[+In, ?Yield, ?Await]opt:AssignmentExpression[+In, ?Yield, ?Await]opt] 1933 | 1934 | 1935 | 1936 | CallExpression[Yield, Await]:CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await] 1937 | SuperCall[?Yield, ?Await] 1938 | ImportCall[?Yield, ?Await] 1939 | CallExpression[?Yield, ?Await]Arguments[?Yield, ?Await] 1940 | CallExpression[?Yield, ?Await][Expression[+In, ?Yield, ?Await]] 1941 | CallExpression[?Yield, ?Await].IdentifierName 1942 | CallExpression[?Yield, ?Await]TemplateLiteral[?Yield, ?Await, +Tagged] 1943 | CallExpression[?Yield, ?Await][AssignmentExpression[+In, ?Yield, ?Await]opt:AssignmentExpression[+In, ?Yield, ?Await]opt] 1944 | 1945 | 1946 | 1947 | OptionalExpression[Yield, Await]:MemberExpression[?Yield, ?Await]OptionalChain[?Yield, ?Await] 1948 | CallExpression[?Yield, ?Await]OptionalChain[?Yield, ?Await] 1949 | OptionalExpression[?Yield, ?Await]OptionalChain[?Yield, ?Await] 1950 | 1951 | 1952 | OptionalChain[Yield, Await]:?.[Expression[+In, ?Yield, ?Await]] 1953 | ?.IdentifierName 1954 | ?.Arguments[?Yield, ?Await] 1955 | ?.TemplateLiteral[?Yield, ?Await, +Tagged] 1956 | ?.[AssignmentExpression[+In, ?Yield, ?Await]opt:AssignmentExpression[+In, ?Yield, ?Await]opt] 1957 | OptionalChain[?Yield, ?Await][Expression[+In, ?Yield, ?Await]] 1958 | OptionalChain[?Yield, ?Await].IdentifierName 1959 | OptionalChain[?Yield, ?Await]Arguments[?Yield, ?Await] 1960 | OptionalChain[?Yield, ?Await]TemplateLiteral[?Yield, ?Await, +Tagged] 1961 | OptionalChain[?Yield, ?Await][AssignmentExpression[+In, ?Yield, ?Await]opt:AssignmentExpression[+In, ?Yield, ?Await]opt] 1962 | 1963 | 1964 | 1965 |

7.1 Static Semantics: AssignmentTargetType

1966 | 1967 | 1968 | MemberExpression:MemberExpression[AssignmentExpressionopt:AssignmentExpressionopt] 1969 | 1970 | 1971 | CallExpression:CallExpression[AssignmentExpressionopt:AssignmentExpressionopt] 1972 | 1973 |
  1. Return invalid.
1974 |
1975 | 1976 | 1977 |

7.2 Runtime Semantics

1978 | 1979 |

7.2.1 Runtime Semantics: EvaluateSliceNotation ( baseValue, startExpression, endExpression )

1980 |

The abstract operation EvaluateSliceNotation takes as arguments a baseValue (an ECMAScript langauge value), startExpression (a Parse Node), and endExpression (a Parse Node). It performs the following steps:

1981 |
  1. If the startExpression is present, then
    1. Let startRef be the result of evaluating the startExpression.
    2. Let start be ? GetValue(startRef).
  2. Else,
    1. Let start be 0.
  3. If the endExpression is present, then
    1. Let endRef be the result of evaluating the endExpression.
    2. Let end be ? GetValue(endRef).
  4. Else,
    1. Let end be undefined.
  5. Let base be ? ToObject(baseValue).
  6. Let method be ? GetMethod(base, @@slice).
  7. Return ? Call(method, base, « start, end »).
1982 |
1983 | 1984 | 1985 |

7.2.2 Runtime Semantics: Evaluation

1986 | 1987 | MemberExpression:MemberExpression[AssignmentExpressionopt:AssignmentExpressionopt] 1988 | 1989 |
  1. Let baseReference be the result of evaluating MemberExpression.
  2. Let baseValue be ? GetValue(baseReference).
  3. Let startExpression be the first AssignmentExpression.
  4. Let endExpression be the second AssignmentExpression.
  5. Return ? EvaluateSliceNotation(baseReference, startExpression, endExpression).
1990 | 1991 | 1992 | CallExpression:CallExpression[AssignmentExpressionopt:AssignmentExpressionopt] 1993 | 1994 |
  1. Let baseReference be the result of evaluating CallExpression.
  2. Let baseValue be ? GetValue(baseReference).
  3. Let startExpression be the first AssignmentExpression.
  4. Let endExpression be the second AssignmentExpression.
  5. Return ? EvaluateSliceNotation(baseValue, startExpression, endExpression).
1995 |
1996 | 1997 | 1998 |

7.2.3 Runtime Semantics: ChainEvaluation

1999 |

With parameters baseValue and baseReference.

2000 | 2001 | OptionalChain:?.[AssignmentExpressionopt:AssignmentExpressionopt] 2002 | 2003 |
  1. Let startExpression be the first AssignmentExpression.
  2. Let endExpression be the second AssignmentExpression.
  3. Return ? EvaluateSliceNotation(baseValue, startExpression, endExpression).
2004 | 2005 | 2006 | OptionalChain:OptionalChain[AssignmentExpressionopt:AssignmentExpressionopt] 2007 | 2008 |
  1. Let optionalChain be OptionalChain.
  2. Let newBaseReference be ? ChainEvaluation of optionalChain with arguments baseValue and baseReference.
  3. Let newBaseValue be ? GetValue(newBaseReference).
  4. Let startExpression be the first AssignmentExpression.
  5. Let endExpression be the second AssignmentExpression.
  6. Return ? EvaluateSliceNotation(newBaseValue, startExpression, endExpression).
2009 |
2010 |
2011 |
2012 |
-------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "proposals-slice-notation", 4 | "description": "A proposal to add slice notation to ECMAScript", 5 | "scripts": { 6 | "build": "ecmarkup spec.emu index.html" 7 | }, 8 | "homepage": "https://github.com/tc39/proposal-slice-notationt#readme", 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/tc39/proposal-slice-notation.git" 12 | }, 13 | "license": "MIT", 14 | "devDependencies": { 15 | "ecmarkup": "^3.11.5" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /spec.emu: -------------------------------------------------------------------------------- 1 |
  2 |   title: Slice notation
  3 |   status: proposal
  4 |   stage: 1
  5 |   location: https://github.com/tc39/proposal-slice-notation
  6 |   copyright: false
  7 |   contributors: Sathya Gunasekaran
  8 | 
9 | 10 | 11 |

Well-Known Symbols

12 |

Well-known symbols are built-in Symbol values that are explicitly referenced by algorithms of this specification. They are typically used as the keys of properties whose values serve as extension points of a specification algorithm. Unless otherwise specified, well-known symbols values are shared by all realms ().

13 |

Within this specification a well-known symbol is referred to by using a notation of the form @@name, where “name” is one of the values listed in .

14 | 15 | 16 | 17 | 18 | 21 | 24 | 27 | 28 | 29 | 32 | 35 | 38 | 39 | 40 |
19 | Specification Name 20 | 22 | [[Description]] 23 | 25 | Value and Purpose 26 |
30 | @@slice 31 | 33 | *"Symbol.slice"* 34 | 36 | A method that slices the receiver based on a start and end index. 37 |
41 |
42 |
43 | 44 | 45 |

Properties of the Symbol Constructor

46 | 47 |

Symbol.slice

48 |

The initial value of `Symbol.slice` is the well known symbol @@slice ().

49 |

This property has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *false* }.

50 |
51 |
52 | 53 | 54 |

Properties of the Array Prototype

55 | 56 |

Array.prototype [ @@slice ] (start, end)

57 |

The initial value of the @@slice property is the same function object as the initial value of the `Array.prototype.slice` property.

58 |
59 |
60 | 61 | 62 |

Properties of the %TypedArray.prototype% Object

63 | 64 |

%TypedArray%.prototype [ @@slice ] (start, end)

65 |

The initial value of the @@slice property is the same function object as the initial value of the `%TypedArray%.prototype.slice` property.

66 |
67 |
68 | 69 | 70 |

Properties of the ArrayBuffer Prototype Object

71 | 72 |

ArrayBuffer.prototype [ @@slice ] (start, end)

73 |

The initial value of the @@slice property is the same function object as the initial value of the `ArrayBuffer.prototype.slice` property.

74 |
75 |
76 | 77 | 78 |

Properties of the SharedArrayBuffer Prototype Object

79 | 80 |

SharedArrayBuffer.prototype [ @@slice ] (start, end)

81 |

The initial value of the @@slice property is the same function object as the initial value of the `SharedArrayBuffer.prototype.slice` property.

82 |
83 |
84 | 85 | 86 |

Left-Hand-Side Expressions

87 |

Syntax

88 | 89 | MemberExpression[Yield, Await] : 90 | PrimaryExpression[?Yield, ?Await] 91 | MemberExpression[?Yield, ?Await] `[` Expression[+In, ?Yield, ?Await] `]` 92 | MemberExpression[?Yield, ?Await] `.` IdentifierName 93 | MemberExpression[?Yield, ?Await] TemplateLiteral[?Yield, ?Await] 94 | SuperProperty[?Yield, ?Await] 95 | MetaProperty 96 | `new` MemberExpression[?Yield, ?Await] Arguments[?Yield, ?Await] 97 | MemberExpression[?Yield, ?Await] `[` AssignmentExpression[+In, ?Yield, ?Await]? `:` AssignmentExpression[+In, ?Yield, ?Await]? `]` 98 | 99 | 100 | 101 | CallExpression[Yield, Await] : 102 | CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await] #callcover 103 | SuperCall[?Yield, ?Await] 104 | ImportCall[?Yield, ?Await] 105 | CallExpression[?Yield, ?Await] Arguments[?Yield, ?Await] 106 | CallExpression[?Yield, ?Await] `[` Expression[+In, ?Yield, ?Await] `]` 107 | CallExpression[?Yield, ?Await] `.` IdentifierName 108 | CallExpression[?Yield, ?Await] TemplateLiteral[?Yield, ?Await, +Tagged] 109 | CallExpression[?Yield, ?Await] `[` AssignmentExpression[+In, ?Yield, ?Await]? `:` AssignmentExpression[+In, ?Yield, ?Await]? `]` 110 | 111 | 112 | 113 | OptionalExpression[Yield, Await] : 114 | MemberExpression[?Yield, ?Await] OptionalChain[?Yield, ?Await] 115 | CallExpression[?Yield, ?Await] OptionalChain[?Yield, ?Await] 116 | OptionalExpression[?Yield, ?Await] OptionalChain[?Yield, ?Await] 117 | 118 | OptionalChain[Yield, Await] : 119 | `?.` `[` Expression[+In, ?Yield, ?Await] `]` 120 | `?.` IdentifierName 121 | `?.` Arguments[?Yield, ?Await] 122 | `?.` TemplateLiteral[?Yield, ?Await, +Tagged] 123 | `?.` `[` AssignmentExpression[+In, ?Yield, ?Await]? `:` AssignmentExpression[+In, ?Yield, ?Await]? `]` 124 | OptionalChain[?Yield, ?Await] `[` Expression[+In, ?Yield, ?Await] `]` 125 | OptionalChain[?Yield, ?Await] `.` IdentifierName 126 | OptionalChain[?Yield, ?Await] Arguments[?Yield, ?Await] 127 | OptionalChain[?Yield, ?Await] TemplateLiteral[?Yield, ?Await, +Tagged] 128 | OptionalChain[?Yield, ?Await] `[` AssignmentExpression[+In, ?Yield, ?Await]? `:` AssignmentExpression[+In, ?Yield, ?Await]? `]` 129 | 130 | 131 | 132 |

Static Semantics: AssignmentTargetType

133 | 134 | 135 | MemberExpression : 136 | MemberExpression `[` AssignmentExpression? `:` AssignmentExpression? `]` 137 | 138 | CallExpression : 139 | CallExpression `[` AssignmentExpression? `:` AssignmentExpression? `]` 140 | 141 | 142 | 1. Return ~invalid~. 143 | 144 |
145 | 146 | 147 |

Runtime Semantics

148 | 149 |

Runtime Semantics: EvaluateSliceNotation ( _baseValue_, _startExpression_, _endExpression_ )

150 |

The abstract operation EvaluateSliceNotation takes as arguments a _baseValue_ (an ECMAScript langauge value), _startExpression_ (a Parse Node), and _endExpression_ (a Parse Node). It performs the following steps:

151 | 152 | 1. If the _startExpression_ is present, then 153 | 1. Let _startRef_ be the result of evaluating the _startExpression_. 154 | 1. Let _start_ be ? GetValue(_startRef_). 155 | 1. Else, 156 | 1. Let _start_ be 0. 157 | 1. If the _endExpression_ is present, then 158 | 1. Let _endRef_ be the result of evaluating the _endExpression_. 159 | 1. Let _end_ be ? GetValue(_endRef_). 160 | 1. Else, 161 | 1. Let _end_ be *undefined*. 162 | 1. Let _base_ be ? ToObject(_baseValue_). 163 | 1. Let _method_ be ? GetMethod(_base_, @@slice). 164 | 1. Return ? Call(_method_, _base_, « _start_, _end_ »). 165 | 166 |
167 | 168 | 169 |

Runtime Semantics: Evaluation

170 | MemberExpression : MemberExpression `[` AssignmentExpression? `:` AssignmentExpression? `]` 171 | 172 | 1. Let _baseReference_ be the result of evaluating |MemberExpression|. 173 | 1. Let _baseValue_ be ? GetValue(_baseReference_). 174 | 1. Let _startExpression_ be the first |AssignmentExpression|. 175 | 1. Let _endExpression_ be the second |AssignmentExpression|. 176 | 1. Return ? EvaluateSliceNotation(_baseReference_, _startExpression_, _endExpression_). 177 | 178 | 179 | CallExpression : CallExpression `[` AssignmentExpression? `:` AssignmentExpression? `]` 180 | 181 | 1. Let _baseReference_ be the result of evaluating |CallExpression|. 182 | 1. Let _baseValue_ be ? GetValue(_baseReference_). 183 | 1. Let _startExpression_ be the first |AssignmentExpression|. 184 | 1. Let _endExpression_ be the second |AssignmentExpression|. 185 | 1. Return ? EvaluateSliceNotation(_baseValue_, _startExpression_, _endExpression_). 186 | 187 |
188 | 189 | 190 |

Runtime Semantics: ChainEvaluation

191 |

With parameters _baseValue_ and _baseReference_.

192 | OptionalChain: `?.` `[` AssignmentExpression? `:` AssignmentExpression? `]` 193 | 194 | 1. Let _startExpression_ be the first |AssignmentExpression|. 195 | 1. Let _endExpression_ be the second |AssignmentExpression|. 196 | 1. Return ? EvaluateSliceNotation(_baseValue_, _startExpression_, _endExpression_). 197 | 198 | 199 | OptionalChain: OptionalChain `[` AssignmentExpression? `:` AssignmentExpression? `]` 200 | 201 | 1. Let _optionalChain_ be |OptionalChain|. 202 | 1. Let _newBaseReference_ be ? ChainEvaluation of _optionalChain_ with arguments _baseValue_ and _baseReference_. 203 | 1. Let _newBaseValue_ be ? GetValue(_newBaseReference_). 204 | 1. Let _startExpression_ be the first |AssignmentExpression|. 205 | 1. Let _endExpression_ be the second |AssignmentExpression|. 206 | 1. Return ? EvaluateSliceNotation(_newBaseValue_, _startExpression_, _endExpression_). 207 | 208 |
209 |
210 |
211 | --------------------------------------------------------------------------------