@kangax’ve created a quiz, it’s very interesting, the solution explains a tricky moment of spec.
Question 1
(function(x, f = () => x) {
var x;
var y = x;
x = 2;
return [x, y, f()];
})(1);
- [2, 1, 1]
- [2, undefined, 1]
- [2, 1, 2]
- [2, undefined, 2]
As we know, parameters create extra scope in case of using default values.
- Local variable
xshadows the parameter with the same name,var x - It’s hoisted and assigned to default value, to
undefined? - Usually yes, but not in this case.
- If there is a parameter with the same name, then the local binding is initialize not to
undefinedbut with value of that parameter, that is1 - The variable
ygets the the value1as well, becausevar y = x; xis assigned to2,x = 2;- Now it’s tricky
f(). It is created in thescope of parameters, soxrefers to the parameterx, which is1. - Final values are
[2, 1, 1]
Question 2
(function() {
return [
( () => this.x ).bind({ x: 'inner' }),
( () => this.x )()
];
})().call({ x: 'outer' });
- [‘inner’, ‘outer’]
- [‘outer’, ‘outer’]
- [undefined, undefined]
- Error
Arrow function have lexical this value. This means that, it inherits this value from the context they are defined.
And later it stays unchangeable, even if explicitly bound or called with different context.
In this case both arrow function are created within the context of {x: 'outer'}, and bind({x: 'inner'}) applied on the first arrow function doesn’t make a difference.
Question 3
let x, { x: y = 1} = { x }; y;
- undefined
- 1
- { x: 1}
- Error
let xdefinesxwith valueundefined- Destructive assignment
{ x: y = 1} = { x }, on the right side has a short notation for an object literal -{ x }which is equalent to{ x: x }, that is in our case an object{ x: undefined } - Once it destucted the pattern
{ x: y = 1}, we extract variabley, which correspond to the properyx. Since properyxisundefined, the default value1is assigned to it.
Question 4
(function() {
let f = this ? class g {} : class h {};
return [
typeof f,
typeof h
]
})()
- [‘function’, undefined]
- [‘function’, ‘function’]
- [‘function’, ‘function’]
- [‘undefined’, ‘undefined’]
- Error
- The IIFE is executed with no explicit
thisvalue. In ES6 or withuse strictdirective it means it will beundefined; - So variable
fis a reference toclass h {}. It’s type is afunctionbecause essentially classes in ES6 are syntactic sugar on top ofcontructor function. - However, the
class h {}is created in expression position, that meanshisn’t added to to the environment, and returnundefined.
Question 5
(typeof (new (class { class () {} })))
- ‘function’
- ‘object’
- ‘undefined’
- Error
This is an obfuscated syntax playing, let’s try to figure it out!
- The ES6 allow concise method definition, that allows dropping the
: functionpart. Soclass () {}is a method inside in https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/class#Examples. - Now instead of assigning it to variable, we can instantiate it directly:
new class { class() { } } - The result of default class is always an object. So
typeofshould returnobject.
Question 6
typeof (new (class F extends (String, Array) { })).substring
- ‘function’
- ‘object’
- ‘undefined’
- Error
Again an obfuscated syntax.
- The grouping operator always return the last argument, so the result of
(String, Array)is actually justArray - So we get
class F extends Array {} - We can image as it’s assigning operation
let f = new F - Obviously that
typeof f.substringisundefined
Question 7
[...[...'...']].length
- 1
- 3
- 6
- Error
The spread operator allows to spread all the elements to the array. It works with any iterable object.
- String are iterable, meaning that we can iterate char by char. So inner
[...'...']results to an array['.', '.', '.'] - Array is iterable as well, so outer array spreads into new array.
- Result of
['.', '.', '.'].lengthis3
Question 8
typeof (function* f() { yield f })().next().next()
- Generator object has
nextmethod, that returns the next value at theyieldposition. The returned value has signature:{ value: <returned value>, done: boolean} - First
g.next()has result{value: function f, done: false} - The returned value value itself doesn’t have
next()method, so trying to chain methods is an error.
Question 9
typeof (new class f() { [f]() { }, f: { } })[`${f}`]
- ‘function’
- ‘undefined’
- ‘object’
- Error
Since the syntax of class isn’t correct class f(), the result is an error.
Question 10
typeof `${{Object}}`.prototype
- “function”
- “undefined”
- “object”
- Error
That one is very tricky!
We have something that looks a bit strange: it isn’t ${Object} how it “should be”, but the ${{Object}}. It isn’t a special syntax it is still a value {Object} in template string ${}.
- What is
${Object}? ES6 has short notation for object literal, so in fact it’s just:{Object: Object}, a simple object with the property named'Object', and the valueObject(the built in constructor). - So
${ {Object: Object} }, become'[object Object]'. Because the${x}is roughly equivalent to thex + ''orx.toString() - Now the
'[object Object]'.prototypeisundefined
Save my day: * DmitrySoshnikov