ES6 in Chromium proposal: destructing

72 views
Skip to first unread message

man...@chromium.org

unread,
Dec 3, 2018, 1:43:49 PM12/3/18
to Chromium-dev, Demetrios Papadopoulos, Phistuck Cashewa, Mike Frysinger, Scott Chen, Christopher Lam, Dan Beam, Hector Carmona, Esmael El-Moslimany, Rebekah Potter, Tommy Li
Originally posted as a comment in the spread & rest proposal, but re-posting as it's own thread per suggestion.


Proposing to move destructuring to the "allowed features" section of the es style guide.

Syntax

let [one, two] = [1, 2];
let 
{ten, eleven} = {ten: 10, eleven: 11};


// skipping
let 
[one, two, , four] = [1, 2, 3, 4];
let 
{ten, eleven, thirteen} = {ten: 10, eleven: 11, twelve: 12, thirteen: 13};


// renaming
let 
{ten, x: eleven} = {ten: 10, x: 11, twelve: 12};


// unwrapping nested objects
let 
{wrap: {wrap2: {fifty}}} = {wrap: {wrap2: {fifty: 50}}};


// default values
let 
[zero = 0, xnull = 0, xfalse = 0] = [undefined, null, false];
let 
{cats = 0, dogs = 0, firstName = '', lastName = ''} = {dogs: 3, firstName: 'x'};
let 
{surname: lastName = ''} = {surname: 'false'};

Benefits

1. Conciseness

Before

people.forEach(person => {
  processFirstName
(person.name.first);
  processLastName
(person.name.last);
  processAge
(person.age);
  processFull
(`${person.name.first} ${person.name.last}`, person.age);
});

Or

people.forEach(person => {
  let first 
= person.name.first;
  let 
last = person.name.last;
  let age 
= person.age;
  processFirstName
(first);
  processLastName
(last);
  processAge
(age);
  processFull
(`${first} ${last}`, age);
});

After

people.forEach(({name: {first, last},  age}) => {
  processFirstName
(first);
  processLastName
(last);
  processAge
(age);
  processFull
(`${first} ${last}`, age);
});

2. Explicit function interfaces

Before

// unclear what the parameter `settings` should look like without looking at sample invocations.
function updatePage(settings) {};

After

function updatePage({bgColor, fontColor, fontSize}) {};

This issue is mitigated when type annotations are available.

3. Explicit naming of array items

Before

let htmlText = '<p>The blue fox ate the moon grass.</p>';
let textRegex 
= /\>([A-Z]\w+) ((?:\w|\s)*)([.!?])?\</;
let lineMatch 
= htmlText.match(textRegex);

printLarge
(lineMatch[1]);
print(lineMatch[2]);
printOrDefault
(lineMatch[3], '.');

Or

let htmlText = '<p>The blue fox ate the moon grass.</p>';
let textRegex 
= /\>([A-Z]\w+) ((?:\w|\s)*)([.!?])?\</;
let lineMatch 
= htmlText.match(textRegex);
let firstWord 
= lineMatch[1];
let remainingSentence 
= lineMatch[2];
let punctuation 
= lineMatch[3];

printLarge
(firstWord);
print(remainingSentence);;
printOrDefault
(punctuation, '.');

After

let htmlText = '<p>The blue fox ate the moon grass.</p>';
let textRegex 
= /\>([A-Z]\w+) ((?:\w|\s)*)([.!?])?\</;
let 
[, firstWord, remainingSentence, punctuation] = htmlText.match(textRegex);


printLarge
(firstWord);
print(remainingSentence);
printOrDefault
(punctuation, '.');

With Rest operator

Worth noting, destructuring and rest operator can be used together.
let [first, second, third, ...honorableMentions] = [0, 1, 2, 3, 4, 5, 6, 7]; // see [1]
let 
{president, vicePresident, ...otherImportantPeople} = {president: 0, vicePresident: 1, depStateSec: 2, depDefenseSec: 3, depTreasurySec: 4} // see [2]

Compatibility:
Works with eslint, clang, and Closure [see below]
[1] Rest operator in array destructuring is not supported by iOS.
[2] Rest operators in object destructuring is supported by iOS 11.1+ and closure compiler with `ECMASCRIPT8` flag.

Closure support

1. Rest operator in object destructuring.

As noted above, this requires the `ECMASCRIPT8` flag.

2. Typed arrays

The below snippet fails to throw a compiler error.

/** @type number */ let one;
[one] = [false];


Similarly, for default values during array deconstruction, the below does not throw an error.

/** @type string */ let zero;
/** @type string */ let xnull;
/** @type string */ let xfalse;
[zero = 0, xnull = 0, xfalse = 0] = [undefined, null, false];


But this is a broader issue with typed arrays in general and not unique to destructuring expressions, e.g. the below also fails to throw an error.

/** @type Array<number> */ let array;
array
= [false];


Therefore, I don't think this is an argument against allowing destructuring, but still something worth mentioning.

Dan Beam

unread,
Dec 3, 2018, 9:21:02 PM12/3/18
to man...@chromium.org, chromi...@chromium.org, Demetrios Papadopoulos, phis...@chromium.org, Mike Frysinger, Scott Chen, Christopher Lam, Hector Carmona, a...@chromium.org, rbpo...@chromium.org, Tommy Li
On Mon, Dec 3, 2018 at 10:04 AM <man...@chromium.org> wrote:
Originally posted as a comment in the spread & rest proposal, but re-posting as it's own thread per suggestion.


Proposing to move destructuring to the "allowed features" section of the es style guide.

Preface: thank you for wanting to participate in this process and make web development in Chromium better :).

I guess my only 2 cents to add here is: many of the simple examples on MDN are great and easy to read:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Browser_compatibility
but some of the more complex ones (i.e. defaults and destructuring and rest, possibly with objects) seem maybe harder to read than just ... "structured" versions.  So maybe add a cautionary note about "don't go nuts / cause code be to be less readable because of this" when/if we allow this.
The combo of rest and destructuring is interesting.  I can see why you originally sent together.
 
Compatibility:
Works with eslint, clang, and Closure [see below]

How did you test each tool?
 
[1] Rest operator in array destructuring is not supported by iOS.
[2] Rest operators in object destructuring is supported by iOS 11.1+ and closure compiler with `ECMASCRIPT8` flag.

I assume you mean we'd have to change language_in to ECMASCRIPT8 in closure_args.gni?
https://cs.chromium.org/chromium/src/third_party/closure_compiler/closure_args.gni?type=cs&sq=package:chromium&g=0&l=40
Has anybody tried this / do we know how much work it'd be?

-- Dan

man...@google.com

unread,
Dec 4, 2018, 11:16:41 AM12/4/18
to Chromium-dev, man...@chromium.org, dpa...@chromium.org, phis...@chromium.org, vap...@chromium.org, scot...@chromium.org, cala...@chromium.org, hcar...@chromium.org, a...@chromium.org, rbpo...@chromium.org, tomm...@chromium.org
How did you test each tool?

iOS: checked the table here https://kangax.github.io/compat-table/es6/

For eslint, clang, and closure, I 
1) added destructuring examples covering the use cases above to the existing file resources/md_bookmarks/list.js, 
2) added closure annotations, 
3) added a few intentional eslint, closure annotation, and formatting errors, 
4) ran the respective commands (see below), 
5) ensured the intentional errors were caught (or reformatted) and no other errors were thrown.

eslint: `git cl presubmit`
clang: `git cl format --js`
closure:
ninja -C out/Default -j 1000 chrome chrome/browser/resources/md_bookmarks:closure_compile

Let me know if one this wasn't sufficient verification.

I assume you mean we'd have to change language_in to ECMASCRIPT8 in closure_args.gni?
https://cs.chromium.org/chromium/src/third_party/closure_compiler/closure_args.gni?type=cs&sq=package:chromium&g=0&l=40
 
Yes. I meant `ECMASCRIPT_2018` (it's already set to es8 / es2017).

Has anybody tried this / do we know how much work it'd be?

 closure gave a couple of the below errors. I didn't resolve these to see if it would then give more errors.

../../chrome/browser/resources/md_bookmarks/app.js:10: ERROR - Behaviors must be global names or qualified names that are declared as object literals or array literals of other valid Behaviors.
    bookmarks.StoreClient,
    ^^^^^^^^^^^^^^^^^^^^^

../../chrome/browser/resources/md_bookmarks/command_manager.js:11: ERROR - A Polymer() declaration cannot use 'const'.
  const CommandManager = Polymer({
                         ^^^^^^^^^


Regarding the rest operator in object destructuring, it fails eslint as well.


Tommy Li

unread,
Dec 4, 2018, 12:16:17 PM12/4/18
to Dan Beam, man...@chromium.org, chromium-dev, Demetrios Papadopoulos, phis...@chromium.org, vap...@chromium.org, scot...@chromium.org, Christopher Lam, Hector Carmona, a...@chromium.org, rbpo...@chromium.org
+1 to dbeam's suggestion that there should be a disclaimer about using these features judiciously where they add readability.

For instance, if I saw:
  let {wrap: {wrap2: {fifty}}} = {wrap: {wrap2: {fifty: 50}}}; 
  let {cats = 0, dogs = 0, firstName = '', lastName = ''} = {dogs: 3, firstName: 'x'};

in a code review, I'd probably say: whoa calm down there.

That being said, I'm overall very supportive, these two lines, for instance, I think should be a no-brainer Yes:
```
  let [one, two] = [1, 2];
  let 
{ten, eleven} = {ten: 10, eleven: 11};
```

man...@chromium.org

unread,
Jan 9, 2019, 5:15:55 PM1/9/19
to Chromium-dev, db...@chromium.org, man...@chromium.org, dpa...@chromium.org, phis...@chromium.org, vap...@chromium.org, scot...@chromium.org, cala...@chromium.org, hcar...@chromium.org, a...@chromium.org, rbpo...@chromium.org
Update on iOS compatibility,

I originally mentioned iOS 10 does not support rest syntax in destructuring arrays or objects.
I've tried on an iOS 10 simulator on mac; it actually does support rest syntax in destructuring arrays, but not objects.

let [one, ...twoAndThree] = [1, 2, 3]; // iOS 10 compatible

let
{four, ...fiveAndSix} = {four: 4, five: 5, six: 6}; // iOS 10 incompatible

Worth noting,
According to MDN, iOS 10 supports neither. This is inconsistent with my observations.
According to the kangax table, iOS supports rest syntax in array destructuring; but it does not indicate whether rest syntax in object destructuring is supported or not.
Reply all
Reply to author
Forward
0 new messages