Question 1:

The most complex question for me in this quiz. I didn't get it right initially until read the spec and clarified with @kangax. First I answered [2, undefined, 1], which is "almost correct", except one subtle thing. The correct answer here is the first one, [2, 1, 1], and let's see why.

Parameter f is always the function (the default value, since it's not passed), and it capturesx exactly from the parameters scope, that is 1.

Local variablexshadows the parameter with the same name, var x;. It's hoisted, and is assigned default value... undefined? Yes, usually it would be assigned value undefined, but not in this case, and this is the subtle thing we mentioned. If there is a parameter with the same name, then the local binding is initialized not with undefined, but with the value (including default) of that parameter, that is 1.

So the variable y gets the value 1 as well, var y = x;.

Next assignment to local variable x happens, x = 2, and it gets value 2.

By the time of the return, we have x is 2, y is 1, and f() is also 1. It's also a tricky part: since f was created in the scope of parameters, its x refers to the parameterx, which is still 1.

And the final return value is: [2, 1, 1].

Question 2:

Arrow functions have lexical this value. This means, they inherit this value from the context they are defined. And later it stays unchangeable, even if explicitly bound or called in a different context.

In this case both arrow functions are created within the context of {x: 'outer'}, and .bind({ x: 'inner' }) applied on the first function doesn't make difference.

So the answer is: ['outer', 'outer'].

Question 3:

let x, { x: y =1 } = { x }; y;

undefined

1

{ x: 1 }

Error

Variable y will eventually have value 1 since:

First, let x defines x with the value undefined.

Then, destructuring assignment{ x: y = 1 } = { x } on the right hand side has a short notation for an object literal: the {x} is equivalent to {x: x}, that is an object {x: undefined}.

Once it's destructured the pattern { x: y = 1 }, we extract variable y, that corresponds to the property x. However, since property x is undefined, the default value1 is assigned to it.

Question 4:

This IIFE is executed with no explicit this value. In ES6 it means it will be undefined (the same as in strict mode in ES5).

So the variable f is bound to the class h {}. Its typeof is a "function", since classes in ES6 is a syntactic sugar on top of the constructor functions.

However, the class h {} itself is created in the expression position, that means its name his not added to the environment. And testing the typeof h should return "undefined".

And the answer is: ["function", "undefined"].

Question 5:

(typeof (new (class { class () {} })))

"function"

"object"

"undefined"

Error

This is an obfuscated syntax playing, but let's try to figure it out :)

First of all, since ES5 era, keywords are allowed as property names. So on a simple object example, it can look like:

let foo = {
class:function() {}
};

And ES6 standardized concise method definitions, that allows dropping the : function part, so we get the:

let foo = {
class() {}
};

This is exactly what corresponds to the inner class () {} -- it's a method inside a class.

The class itself is anonymous, so we can rewrite the example:

let c =class {
class() {}
};
newc();

Now, instead of assigning to the varialbe c, we can instantiate it directly:

newclass {
class() {}
};

The result of a default class is always a simple object. And its typeof should return "object":

typeof (newclass {
class() {}
});

And the answer is: "object".

Quetion 6:

typeof (new (classFextends (String, Array) { })).substring

"function"

"object"

"undefined"

Error

Here we have a similar obfuscated example (but we already figured out this inlined typeof, new, and class thing above ;)), though the interesting part is the value of the extends clause. It's the: (String, Array).

The grouping operator always returns its last argument, so the (String, Array) is actually just Array.

Question 10:

They are capable to render values of variables directly in the strings:

let x =10;
console.log(`X is ${x}`); // "X is 10"

However, in the example we have something that looks a bit strange: it's not ${Object} how it "should be", but the ${{Object}}.

No, it's not another special syntax of template strings, it's still a value inside ${}, and the value is {Object}.

What is {Object}? Well, as we mentioned earlier above, ES6 has short notation for object literals, so in fact it's just the: {Object: Object} -- a simple object with the property named "Object", and the value Object (the built-in Object constructor).

Question 13:

This example is only on attention, since it's a syntax error: the arrow function => cannot be defined in this way, since we have a an object with the g (consice) method.

And the answer is: Error.

Conclusion

I like such tricky quiz questions, it's always fun to track the runtime semantics and parsing process manually. Of course, most of the things here are far from practical production code, and are interesting mostly from the theoretical viewpoint. Still I found it enjoyable.

This comment has been minimized.

I think you failed more tests than you think, or maybe the test changed its results since this morning (there were less Errors IIRC). Anyway, one thing I'd like to underline, the this as well as arguments with arrow functions are problematic and could fail once transpiled.

So, the expression ([{ x: 1 }, 2, { y }]) seems to be evaluated in an environment where x and y are defined, but they haven't been initialized yet (TDZ) and that's why it errors (not because y doesn't exist but because it is uninitialized).

There is. ES6 moved this from the execution context to the environment record, and exactly in order to preserve it lexically, when an arrow function is created and captures that environment.

Of course, any other function would capture the same environment with lexical this sitting there, but on practice it's observable only with arrow functions because any other function sets a dynamic this (in a newly created, activation environment) at calling, as always was. So when ResolveThisBinding is called, it of course finds this directly in the first, activation environment.

In contrast, arrow functions do not receive direct [[thisValue]] in their activation environment, and it is resolved in the scope chain, and is found in the first environment that defined it.

That's said, in ES5 environment never contained this, it was on execution context, and in ES6 it's always there except for arrows.

So there definitely is lexical this: technically it's always lexical, since is captured by a function in the environment, and practically is observed only for arrows (that directly correspond to their [[ThisMode]] which is "lexical").

This comment has been minimized.

...means there's no lexical this in the arrow function itself, in which case it's looked up lexically in the scope chain; exactly as you've described. so, nothing to worry about here. @WebReflection was only pointing out how most people don't understand that, and referencing my blog post which tries to clear it up.

This comment has been minimized.

@DmitrySoshnikov I meant what @getify said and I've probably abused the word "transpiled" ... most explanations about arrow functions are superficially comparing it against .bind(context) but there's much more than that. Babel transpiles it right but AFAIK traceour had a bug. Thinking arrow just as bind with a single argument is also wrong and thinking about any this or any arguments mechanism within fat arrow makes basically no sense.

Thanks for the other edit about the 12th, I guess I've got that wrong too then last morning.

This comment has been minimized.

edited

The same result with babel-node 6.7.5. As it stated in "Exploring ES6" book, var does nothing if parameter with same name exists. And looks like it is working that way. after var x line, x still have binding to parameter, not to a new variable inside function body scope. So assignment x = 2 will change parameter itself because there is no x variable in function body scope which shadows parameter.

This comment has been minimized.

edited

#3:

Not sure if i understood you but i think you're wrong.

let x, { x: y = 1 } = { x }; y;

First it creates a variable 'x' without any value so it's set to 'undefined';
After it, an object is defined with one property 'x' that takes the value of 'y' which is automatically created global with value '1'.
Next, this object is assigned to an object declared like this {x}. This 'x' is taking the value of the first 'let x' so that is the same as write '{x: undefined}', but this is totally irrelevant for the final result.
Then we print the global 'y' variable defined in the first object declaration.