Recently some JavaScript quizzes appear then and there with the competitive titles wondering whether “you know JavaScript”? The recent quizzes were by kangax, Dmitry Baranovskiy and by Nicholas C. Zakas. All that quizzes are interesting, many questions though are mostly theoretical rather than practical.
And again just for fun, I suggest another ECMAScript quiz. I won’t use some boring things such as “a+++b”; but I will more sophisticated 😉 Some interesting questions are collected from newsgroups, mailing lists, forums and from my own.
Some features and difficulty level:
- almost all questions are theoretical; some of them are directly related to ECMA-262-3 specification;
- clear ECMAScript is used without non-standard features, augmentations of built-ins or any other extensions, though can be the case of user-defined global objects;
- objectively, the test is hard, but should not be so if you will be attentive;
- there are hard and easy questions;
- there are questions only on attention;
- if some questions seem to be hard, you can use console (that’s not a cheating, because some questions are hard).
- what’s the goal, when and where will I need to use this “useless” stuff on practice? – Usually, you won’t. This test is mostly theoretical, you may pass it or may not – that’s your choice.
Good luck.
typeof typeof(null)
2. Are the algorithms of the following checks completely equvalent?
typeof foo == 'undefined'
and
typeof foo === 'undefined'
100['toString']['length']
var a = (1,5 - 1) * 2
var x = 10; var foo = { x: 20, bar: function () { var x = 30; return this.x; } }; console.log( foo.bar(), (foo.bar)(), (foo.bar = foo.bar)(), (foo.bar, foo.bar)() );
function f(x, y) { x = 10; console.log( arguments[0], arguments[1] ); } f();
var b = 10, c = ( 20, function (x) { return x + 100}, function () { return arguments[0]} ); a = b + c ({x: 10}).x
1..z
({ x: 10, foo: function () { function bar() { console.log(x); console.log(y); console.log(this.x); } with (this) { var x = 20; var y = 30; bar.call(this); } } }).foo();
foreach (k in {a: 10, b: 20}) { // ... }
Good stuff.
I messed up #9, thinking that `x` in `x, y, this.x` has value of `20`, not `undefined`. Then realized where the mistake was (`bar`’s VO is followed by `foo`’s VO, not the object that `with` injected into the scope; lexical scoping keeps biting me from time to time :-)).
Minor nitpicks: question #2 is debatable. I kind of understand what you mean by “[…] algorithms of the following checks completely equivalent”, but if we were to be precise, ‘undefined’ == ‘undefined’ and ‘undefined’ === ‘undefined’ go through different algorithms. Former one goes through “The Abstract Equality Comparison Algorithm” (11.9.3), whereas latter one — through “The Strict Equality Comparison Algorithm” (11.9.6). Both go through steps 1,2,3,4 and 11, but step 1 in 11.9.3 is technically not the same as step 1 in 11.9.6. Therefore, I can say that algorithms are different.
Finally, just as I mentioned on Zakas blog (http://www.nczonline.net/blog/2010/02/16/my-javascript-quiz/#comment-4568), it’s better to stay away from host objects (e.g. `alert`) as their unspecified nature makes questions ambiguous.
Снова 50/50 =(
В последнем совсем ступил и посмотрел не туда.
Объясните пожалуйста 5 вопрос, почему так, можно со ссылками на спецификацию
Allright, I’ll bite… #2: two distinct algorithms are applied (but in effect they do the same thing, yes). #3: very nice, totally forgot about the radix parameter. #5: I do believe this should be 20,10,10,10, not 20,20,10,10 (the accepted solution). I had #6 wrong, but the result is just a comma, not “undefined”, when you alert it. #9 is a “with” scoping problem i never get right and #10 totally got me 🙂 (5/5)
Good questions. All of these are related with specification, and there are no host objects. Would be great if, there site with quiz like yours and @kangax. People can improve their knowledge about ECMA-262 3 and perhaps 5 editions.
Regarding semicolon insertions:
a) SyntaxError
b) Transform to `;false;`
a) Syntax error
b) Transform to `;false;`
A wonderful test. Congratulations.
@qFox, #5, (foo.bar)() is exactly the same as foo.bar():
11.1.6 The Grouping Operator
The production PrimaryExpression : ( Expression ) is evaluated as follows:
1. Evaluate Expression. This may be of type Reference.
2. Return Result(1).
Again regarding ASI. I see in ECMA-262 5, there still rules for automatic semicolon. And strict mode doesn’t make any sense about this. That is one of the “features”, which is total misconceptions in language. I can’t see any reasons to skip semicolon. I always put explicitly semicolon. Semicolon insertion is job for developer, not for Tokenizator of the language. Automatic insertion is bad design. That design is developed for people, which don’t give a damn about, where actually need semicolon. If developer doesn’t know where need be put semicolon, he should be read specification of the language, not rules for automatic semicolon insertion. Of course ES5 cannot remove automatic insertion because will break backward compatible. But i am wonder, why in strict mode, there still rules for ASI?
Regards for good question, and will be great if you post explanations about correct behavior.
Perhaps will be good if you create your own site in which you can post your articles, quiz’s and other things about ES. There you can build content on different languages, and for readers will be easy to understand your suggestions and articles. ;~)
update:
Question #4 is changed from:
The correct answer was set to “global”. But this question is very ambiguous. By ES3 it should be “Catch-object with “e” property” although only some implementation conform to it (spec doesn’t say directly about this, though I myself was wondering once why this value in implementations is global but not catch-value) – you can see conforming implementations e.g. in Opera 10.10, or in current version of Rhino – they will return catch-object in this case.
But in ES5 this was recognized as a bug, and this value in this case should be set to global. So from the ES5 viewpoint the answer was correct. And if I directly mentioned in disclaimer that questions are for ES3, for do not make this question ambiguous, I decided to change this question on current (provided by @DmitryKorobkin):
Thanks to @ohunt
Dmitry.
Thanks all who already passed the test. I necessarily will answer all questions but a bit latter (other may want to pass it too). You sure also can write your explanations to each other – it’s welcomed 😉
But they can use special object for augment Scope Chain during evaluation of `catch` statement. Object which in specification called activation in:
| 11.2.3 Function Calls
| 7. If Result(6) is an activation object, Result(7) is null.
| Otherwise, Result(7) is the same as Result(6)
Of course here that object isn’t “Activation Object” in context of “10 Execution Contexts”, but behavior is reasonable. You can use “NFE” for observing same behavior.
In second invokation of `f’, `this’ value should reffer object created on:
| 1. Create a new object as if by the expression newObject().
| 2. Add Result(1) to the front of the scope chain.
Great and very sophisticated test, this one totally had me down 😉
Thanks, I learned a lot.
В мене питання щодо тесту #6.
ECMA-262, 3rd Edition, section 10.1.8:
For each non-negative integer, arg, less than the value of the length property, a property is created with name ToString(arg) and property attributes { DontEnum }. The initial value of this property is the value of the corresponding actual parameter supplied by the caller. The first actual parameter value corresponds to arg = 0, the second to arg = 1, and so on. In the case when arg is less than the number of formal parameters for the Function object, this property shares its value with the corresponding property of the activation object. This means that changing this property changes the corresponding property of the activation object and vice versa.
Тобто, на скільки я розумію, грубо кажучи, зміни x і arguments[0] мали б синхронізуватися. Власне, в хромі так і відбувається. В фаєрфоксі – ні. Хто правий і чи не мала б бути там відповідь “10, undefined”?
@Alex Gromov
Моё недавнее объяснение в одном из топиков на Хабре: http://habrahabr.ru/blogs/javascript/84381/#comment_2519403
На форуме http://javascript.ru/forum/, вопрос изначально появился от Zeroglif (там же есть несколько объяснений): http://javascript.ru/forum/misc/5724-secrets-javascript-ninja.html#post34116
ECMA-262-3, 11.2.3 Вызовы функций – http://javascript.ru/ecma/part11#a-11.2.3 (важные пункты 6-8).
@qFox
As already was mentioned bellow, the grouping operator doesn’t call GetValue, so after its work there’s still RefereceType value. Two last call GetValue, so there’re already functions but not value of ReferenceType, which means: this value = null => global.
Yes, there was alert([…]) used, I’ve changed it to console.log(…) which should show undefined.
Dmitry.
@Asen Bozhilov
Yes, the behavior with second call of NFE in this case is also debatable. I guess implementations handle this case somehow specially, they know that if base object is determinate as that special object storing optional name of FE, then also null => global should be used for the this value. But that’s just the guess, I don’t see in spec explanation of it.
Also we know that some implementations create this identifier binding right in the activation object (e.g. Rhino, but the similar behavior we saw in newer versions of Firefox).
But regarding exactly catch clause, ECMA-262-5 really has clarification of this ambiguous “bug” (feature):
From “Annex D (informative). Corrections and Clarifications in the 5th Edition with Possible 3rd Edition Compatibility Impact” of ECMA-262-5:
Dmitry.
@kunik
Seems, you can’t write in Russian, but understand English. So, sorry, I can’t write in your suggested language, and will answer in English.
From ECMA-262-3 10.1.8, bullet 2:
So, in this case (no parameter passed) this property (arguments[0]) doesn’t share its value with the corresponding property of the activation object. And that’s why Chrome is wrong.
Dmitry.
@Asen Bozhilov
Yeah, I’m thinking on it, maybe will be soon.
This questions are very interesting, thanks, Asen. For now I know at least two non-conformant implementations – IE (JScript) and Chrome (V8).
About the first case (ECMA-262-3, 7.4 Comments):
So the answer is (b) – Transform to `;false;`, as still there’s LineTerminator.
About the second case (ECMA-262-3, 7.4 Comments):
So the answer is also (b) – Transform to `;false;`, as again we have one LineTerminator. But IE and Chrome parse this case wrong and have SyntaxError.
Dmitry.
update:
@joseanpg has provided a good explanation of the quiz (you can find it on his twitter page). Although, question #10 became debatable. In disclaimer there was said:
which if to be fair can make answer on question #10 wrong. So I’ve changed this point in disclaimer to:
although, simple global function – is an augmentation of the global object, and the global object – is a built-in object. And to keep this question more interesting (rather than just “Always ReferenceError”), I’ve clarified disclaimer point; but the answer of joseanpg fairly (if there’s no any user-defined functions) is correct too.
The main goal of this question is about automatic semicolon insertion (7.9, ECMA-262-3) and position of the open curly block’s bracket; “foreach” and “k” play minor role here. In contrast with:
which always will provide SyntaxError and thus will help to avoid error in logic of the program if user-defined function “foreach” exists and open curly block’s bracket is set on the new line:
as it will be transformed to:
Dmitry.
@kangax
Yes, that’s it, [[Scope]] of `bar’ is already set; firstly this question appeared on es-discuss mailing list, there is also my explanation: https://mail.mozilla.org/pipermail/es-discuss/2010-February/010791.html
Well, yeah, the main goal of this question is in the same types of operands and which imperative actions are taken applying algorithms. As types are the same, step 1, can be omitted to make this question more interesting than just “No, different algorithms (names) are used”.
The goal is to show that there’s no need to write (how we can see in many frameworks) strict equality with typeof operator and string operand.
About debatable – I think it will be better to form (more) correctly question title. Any suggestions?
Yep, true, I changed it to console.log, which is also, btw, host 😉
Dmitry.
@Asen Bozhilov
Well, actually automatic semicolon insertion there’s in many languages (though, maybe it’s named differently), e.g. in Ruby, QML declarative, other. You can write (in Ruby):
or
the same result.
Yes, that’s true, that ECMAScript has some ambiguous (from the human logic viewpoint) features regarding to ASI (if not to know and not to understand how this mechanism works).
But in general, this idea can be not so bad. The question is in implementation and ES has some ambiguous cases in this place. That’s it.
What about me – I always put semicolon explicitly in ES. And about ES5 – yep, they could force put semicolon explicitly in “strict mode”, but as I already told in some forums – I believe “strict mode” feature itself as an error of language design. Be more exact – the error is not the “strict” technique as itself, but in distinguishing “strict” and “non-strict” modes, which will cause many useless holy wars and debates. Some will talk that’s professional code is only in strict – but that’s completely wrong.
By the truth, I think that ES has a bit overloaded syntax, I think it should omit some redundant C-style features, which is actually done in version 1.8 of SpiderMonkey – as you know there open curly brackets and return keyword in some cases are optional – the same can be with semicolon – maybe that’s why they do not force put it explicitly even in strict mode.
Dmitry.
So, as it was mentioned above, a good explanation of this quiz was provided by @joseanpg and is available here: http://joseanpg.net/jslab/quiz/soshnikov/answers.html.
Another very good explanation of the quiz, by @slicknet: http://www.nczonline.net/blog/2010/02/23/answering-soshnikovs-quiz/ (although, there’re two misconceptions for #3 and #6).
Great test. Learned a lot from it!
I enjoyed the test, and did find it difficult. It’s really interesting though to see how the correct answers differ from output in a Javascript console.
A wonderful test.
I got a few wrong, and after going through them in a js console I now understand why they do what they do (yay!) but I don’t get #10 even if I go through it and change things around. Can you explain what’s going on here so that I can understand JavaScript better?
@Pomax, congrats, understanding 9 of them is a very good result. About #10 — it can be a function call (“foreach” is not a reserved word and since it’s followed by (), it can be treated as a function call; if such a user-defined function exists, it’s not an error, otherwise — the ReferenceError). Detailed answer is here.
I have got some questions about #3. Why does 1.z got “syntax error” when 1..z is legal?
@Melon.h
COPIED FROM http://dmitrysoshnikov.com/ecmascript/chapter-7-2-oop-ecmascript-implementation/#inheritance
I didn’t understand the #7 and #9 questions. Can you please explain? I seen the comment #1 by kangax , but didn’t get exactly what’s happening in #9.
You’ve got 10 mistakes, in questions: #1, #2, #3, #4, #5, #6, #7, #8, #9, #10
great!
@msankhala
On the #7: the result of the comma operator is always the last expression. So
c
is the function which returns its first argument.Then, since
c
is the function, the code:is the same (because semicolon is not inserted at the end of the first line) as:
The #9 is probably the hardest question and relates to static scope rules of JS and semantics of
with
statement. It requires longer explanation which can be found in Chapter 4. Scope chain and also in this quiz’s solutions.Thank a lot Dmitry for such a nice explanation.
You’ve got 2 mistakes, in questions: #5, #7.
I still need to learn a lot 🙂
@Dmitry, please help check my understanding.
To #9 case,
this
inwith
is refer to the most outer object, let’s call itO
, which including {x:10, foo: }.On entering the
foo
contextOn entering the
with
context,with_Object
will added in to scope chain.So
x =20;
will updateO.x
to20
, and localx: undefined
is unchanged,y = 30;
will updatey: undefined
.Consequently, we can get AO of bar
And
this
inconsole.log(this.x)
will resolved toO
, so it will output20
(which isO.x
).So the final result is
undefined, 30, 20
.I think some of my representation is not clear and accurate. Please correct me, thanks.
P.S. Dmitry, I do not know whether
AO
I list are correct or not? I am not sureVOs
of the code, is VO of bar is{globalContext.VO}
? Could you please list allAO
andVO
corresponding to the code?Regards.
@Hong you have correct answer and the line of thinking, however, you’re confused the terminology a bit.
AO can only be for functions. So “AO of O” is not correct terminology, although, it contains correct data in your description.
Also, AO contains only local vars. If a function refers non-local variable (or how we say, free variable), this variable is found in the scope chain of the running context. And the scope chain is formed as:
AO + fn.[[Scope]]
.Also contexts are created only by functions (plus eval and the global context), so the “On entering the with context” is also not correct terminology.
But other than that, your analysis is correct 😉
Please take a look at these answers: http://joseanpg.net/jslab/quiz/soshnikov/answers.html
@Dmitry, thanks for your comment.
Other than that
, seems no other useful info;), maybe I need to re-read your articles.Здравствуйте, Дмитрий!
Спасибо за замечательный тест. У меня есть вопрос, на который пока не могу найти ответа, возможно его можно было бы включить в подобный тест. Почему:
1 < 2 2 > 1 // false
Предположение о том, что имеет значение приоритет операторов не помогает мне ответить на этот вопрос.
Спасибо.
@Ярослав,
Это эквивалентно
Т.к.
Поскольку
Number(true)
— это1
, а1
меньше3
.Соответсвенно,
Т.к.
Дмитрий, скажите, пожалуйста, почему
Ведь преобразование численное.
false
– это0
. Не пустая строка этоtrue
, а значит1
.И правильно ли я понял,
typeof typeof(null)
?Сначала вычисляется
typeof(null) //"object"
Затем
typeof "object" // "string"
@Александр
Строка, содержащая пробельные символы — это
0
в JS.С
typeof
— да, все верно поняли.Nice quiz,
#9 Like many people I like it the most : )
#6 Just for my sense of completion I would add a little twist