@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
x
shadows 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
undefined
but with value of that parameter, that is1
- The variable
y
gets the the value1
as well, becausevar y = x;
x
is assigned to2
,x = 2;
- Now it’s tricky
f()
. It is created in thescope of parameters
, sox
refers 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 x
definesx
with 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 properyx
isundefined
, the default value1
is 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
this
value. In ES6 or withuse strict
directive it means it will beundefined
; - So variable
f
is a reference toclass h {}
. It’s type is afunction
because essentially classes in ES6 are syntactic sugar on top ofcontructor function
. - However, the
class h {}
is created in expression position, that meansh
isn’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
: function
part. 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
typeof
should 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.substring
isundefined
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
['.', '.', '.'].length
is3
Question 8
typeof (function* f() { yield f })().next().next()
- Generator object has
next
method, that returns the next value at theyield
position. 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]'.prototype
isundefined
Save my day: * DmitrySoshnikov