Request for feedback on a talk on I'm giving on ES6

Domenic Denicola domenic at
Sun Oct 21 22:04:26 PDT 2012

Thanks for your help Rick! I've corrected a few, but wasn't sure about some others. Let me know if I'm missing something in the following:

From: Rick Waldron [mailto:waldron.rick at] 
Sent: Sunday, October 21, 2012 17:07

> nit: The comment itself says "// error! used a `let` before declaration.", might be nice to highlight that the error will occur until the let is assigned, ie. I can initialize it, but reads will throw until it's assigned.

If I'm understanding you correctly, you're saying that this should throw?

let x;
assert(x === undefined); // error! Use of `x` before it is assigned.

I was under the impression the temporal dead zone was about use-before-definition, not use-before-assignment. (For const they are the same, since the "Static Semantics: Early Errors" note on page 125 of the spec gives a Syntax Error if the Initialiser is omitted from the LexicalBinding.) That is:

"A let and const declarations define variables that are scoped to the running execution context’s LexicalEnvironment. The variables are created when their containing Lexical Environment is instantiated but may not be accessed in any way until the variable’s LexicalBinding is evaluated. A variable defined by a LexicalBinding with an Initialiser is assigned the value of its Initialiser’s AssignmentExpression when the LexicalBinding is evaluated, not when the variable is created. If a LexicalBinding in a let declaration does not have an an Initialiser the variable is assigned the value undefined when the LexicalBinding is evaluated."

This implies to me that the first line above evaluates the LexicalBinding, assigning the variable the value undefined; since the LexicalBinding is evaluated, the "may not be accessed" clause no longer applies, and no error should occur.

> Not sure of the number, but there is a slide titled "Block Scoping" with this:

> if (Math.random() > 0.5) {
>  function go() {
>    console.log("gone!");
>  }
>  ...
> }
> assert(typeof go === "undefined");

> I'm not sure I get what this one is trying to illustrate, because "go" will always be initialized, regardless of the condition

I believe this is not true. The current semantics for block-scoped functions bind them to the block, not to the surrounding function. (That is, a FunctionDeclaration creates an entry into LexicallyDeclaredNames, not into VarDeclaredNames.)

Even in ES5, this behavior is unspecified: see the "NOTE" under the "Semantics" heading under section 12 of ES5.1, where it notes that even though Statement does not include FunctionDeclaration, implementations often allow it, with "significant and irreconcilable variations." (So, I don't think "go" will always be initialized in all browsers. For example, in IE10 strict mode the above code is a SyntaxError.) It also says that "Future editions of ECMAScript may define alternative portable means for declaring functions in a Statement context."

And indeed, in ES6 the Declaration grammar production is introduced as a sibling to Statement under Block. It includes LexicalDeclaration and FunctionDeclaration; VariableStatements are left under Statement. And the Block Declaration Instantiation algorithm (10.5.4) includes both LexicalDeclarations and FunctionDeclarations, i.e. FunctionDeclarations are added to the block's Declarative Environment Record instead of to the environment record of the containing function.

> new Set(...document.body.children);

> is a Syntax Error, use: 

> new Set([ ...document.body.children ]);

> Same for: 
> new Set(...array)
> Math.max(...array);
> Math.max(0, ...array, 5, ...array2);
> new Date(...dateFields);
> array.push(...array2);

I don't think any of these is a syntax error, since spread works for function calls/constructs too. See or section 11.2.5 of the draft spec wherein the expanded runtime semantics for ArgumentListEvaluation are given (in particular ArgumentList: ...AssignmentExpression and ArgumentList: ArgumentList, ...AssignmentExpression). However, you are right that the sets should be constructed that way, since the Set constructor accepts an iterable and not varargs. Much appreciated!

Also, I just realized that in rearranging my slides I used spread before discussing it -_-. Will need to fix. Maybe "rest and spread" are more comfort than cowpath-paving...

> Weak Sets aren't specified yet. Might be wise to omit that?

Yeah, probably a good place to trim the fat. They are harmonious though, right? Since they're necessary for revocable proxies.

> One of WeakMap's best use cases is private data...

> ... This way any number of methods, both on C's prototype or class-side functions, as long as they are defined in the same scope that "priv" is bound to, can access the private cache in "priv". This beats leaky plain object abstractions for a serious win :)

The problem I've always had with this is that using weak maps for objects you control is silly, when you could just use symbols. Indeed I illustrate the symbol vs. weak map question in my "Symbols Again" slide. Weak maps are more correct for objects you don't control though, due to the possibility of extension-prevented objects (as I plan to point out when that slide comes up). But for the simple private data use case, symbols are great. I was really glad Brendan reminded me that the values are also held weakly, since otherwise weak maps just reduce to a more-cumbersome, but safer, version of symbols.

Again, thanks for your help, and see you tomorrow!

More information about the es-discuss mailing list