Javascript quiz
I was recently reminded about Dmitry Baranovsky’s Javascript test, when N. Zakas answered and explained it in a blog post. First time I saw those questions explained was by Richard Cornford in comp.lang.javascript, although not as thoroughly as by Nicholas.
I decided to come up with my own little quiz. I wanted to keep question not very obscure, practical, yet challenging. They would also cover wider range of topics.
Host objects
Contrary to Dmitry’s test, quiz does not involve host objects (e.g. window), as their behavior is unspecified and can vary sporadically across implementations. We are talking about pure ECMAScript (3rd ed.) behavior. Now, it’s worth pointing out that sometimes implementations deviate from the standard collectively, forming their own, de-facto standard. An example of this is for-in statement, where none of the popular implementations throw TypeError when expression evalutes to null or undefined — for (var prop in null) { ... } — and instead just silently ignore it. I tried to avoid these non-standard cases. Every question has a correct answer that can be reproduced in at least one of the major implementations.
So what are we testing?
Not a lot really. Quiz mainly focuses on knowledge of scoping, function expressions (and how they differ from function declarations), references, process of variable and function declaration, order of evaluation, and a couple more things like delete operator and object instantiation. These are all relatively simple concepts, which I think every professional Javascript developer should know. Most of these are applied in practice quite often. Ideally, even if you can’t answer a question, you should be able to infer answer from specs (without executing the snippet). When creating these questions, I made sure I can answer each one of them off the top of my head, to keep things relatively simple.
Note, however, that not all questions are very practical, so don’t worry if you can’t answer some of them. We don’t often use with statement, for example, so failing to know/remember its exact behavior is understandable.
Few notes about code
- Assuming ECMAScript 3rd edition (not 5th)
- Implementation quirks do not count (assuming standard behavior only)
- Every snippet is run as a global code (not as eval or function one)
- There are no other variables declared (and host environment is not extended with anything beyond what’s defined in specs)
- Answer should correspond to exact return value of entire expression/statement (or last line)
- “Error” in answer indicates that overall snippet results in a runtime error
Quiz
Please make sure you select answer in each question, as lack of answer is not checked and counts as failure. The final score is simply a number of wrong answers, less is better. Quiz requires Javascript to be enabled.
-
1.
(function(){ return typeof arguments; })();
-
2.
var f = function g(){ return 23; }; typeof g();
-
3.
(function(x){ delete x; return x; })(1);
-
4.
var y = 1, x = y = typeof x; x;
-
5.
(function f(f){ return typeof f(); })(function(){ return 1; });
-
6.
var foo = { bar: function() { return this.baz; }, baz: 1 }; (function(){ return typeof arguments[0](); })(foo.bar);
-
7.
var foo = { bar: function(){ return this.baz; }, baz: 1 } typeof (f = foo.bar)();
-
8.
var f = (function f(){ return "1"; }, function g(){ return 2; })(); typeof f;
-
9.
var x = 1; if (function f(){}) { x += typeof f; } x;
-
10.
var x = [typeof x, typeof y][1]; typeof typeof x;
-
11.
(function(foo){ return typeof foo.bar; })({ foo: { bar: 1 } });
-
12.
(function f(){ function f(){ return 1; } return f(); function f(){ return 2; } })();
-
13.
function f(){ return f; } new f() instanceof f;
-
14.
with (function(x, undefined){}) length;
I hope you liked it. Please leave your score in the comments. I’ll try to explain these questions sometime in a near future, unless someone else does it before me. Meanwhile, you can take a look at my articles on function expressions and delete operator, understanding which would help you answer some of these questions, and more importantly, explain their answers.
Ben Cherry said:
#Initially got 4, 6, 7, 8, and 9 wrong. 4 and 6 were a tossup originally, the rest really did confound me. This is an incredible collection of JavaScript knowledge, without devolving into bugs or even generally into the “bad parts”.
I spent time this weekend working through the details with scoping, and the some times suprising “hoisting” mechanism. I was surprised by what I found, especially with the name “arguments”. Article here: http://bit.ly/bodvBe
You’ve got an awesome ability to cover the hardest topics in extreme detail, while creating something remarkably accessible. Keep it up!
rmf said:
#Ouch, I only got 6 correct:
“You’ve got 8 answers wrong (#2, #6, #7, #8, #9, #11, #12, #13).”
I’m no JavaScript expert, but I’d like to think I’m decently versed in the langauge. Clearly I have a lot to learn.
Jake Archibald said:
#I got #3 wrong, so close yet so far.
Ken Snyder said:
#Function expressions and Function declarations are definitely the most convoluted aspect of JavaScript. Especially since behavior differs from browser to browser. Fortunately, developers have the option to stick with simple function syntax (e.g. declarations and anonymous expressions) to avoid the weirdness.
Gabriel Gilini said:
#You’ve got 2 answers wrong (#2, #13).
Very good, but not quite there yet.
I should have paid more attention on #2, and instanceof always gets me confused :)
skim said:
#Can you explain #8? How does the comma work?
fearphage said:
#Some of those were just pure and simple guesses. Can’t wait to see the explanations.
Nikita Vasilyev said:
#“You’ve got 3 answers wrong (#9, #11, #12).”
#11 and #12 is really surprising to me.
James Wheare said:
#Not really got much to add, but you did ask:
Ben Cherry said:
#Nikita:
#11 isn’t so bad. The object being passed into the argument “foo” is simple, it has one property named “foo”. It has no property named “bar”. typeof foo.bar === “undefined”.
#12 relies on knowledge of how hoisting works. All function declarations are hoisted to the top of the scope. The ‘return’ in between is meant to confuse. The name “f” enters the context with the first declaration, but the second overrides the body. Function declarations are always hoisted above variables, but below parameters. They are resolved in their original lexical order.
Matt Kruse said:
#I got #8 and #9 wrong.
#8 still confuses me (the (a,b) syntax is not something I’m used to!)
#9 in IE results in “1function” which was my answer (incorrect). I guess I’m too stuck in IE mode…
Kyle Simpson said:
#I only got #2 wrong initially. I knew “g” wouldn’t exist but I missed that () executing it would throw an error before typeof got to run. :)
I do admit there were 3 or 4 where I put down an answer as an educated guess and then i checked with the console. I was only confident on 8 or 9 of them. Some are tricky where IE will give a different answer than FF, for instance (specifically the ones with named function expressions).
MindstormsKid said:
#You’ve got 2 answers wrong (#3, #14).
Hmm, I should have paid more attention to #2.
Didn’t really think about functions having the length property. Now I know!
Nikita Vasilyev said:
#Ben Cherry,
#11 is really simple, I see it now.
#12 now clear to me, thanks.
Asen Bozhilov said:
#You’ve got 0 answers wrong. However, test are good and related with very important parts of ECMA-262 3 edition.
10.1.3 Variable Instantiation
11.2.1 Property Accessors
11.2.3 Function Calls
13 Function Definition
kangax already explained many of these cases, in article about Named Function Expression and delete operator, but i think, soon he will explain all of these questions and he will give yet another good article.
Thanks.
skim said:
##11 would have worked with foo.foo
Rick said:
#Humbling.
Andy Beeching said:
#Thanks very much for putting this together, more valuable than Dmitry’s I feel for it’s focus on ECMA spec (though that was fun too!) and length :-)
FWIW I got three wrong (#3, #9, #13), though on second pass with console I understood why in all cases (mainly because of your previous articles!)
Andy Tjin said:
#Some explanations:
#2: if you define a function with this syntax, then the second identifier is only available *inside* the function scope. The weird thing is: try running this code in IE8, FF3.5 and Saf4, they will all show different behaviour.
#3: you cannot delete arguments inside a function
#4: the assignments happen from left to right if you regard the comma’s, but from right to left if you regard the equal signs. So the statemenet is equivalent to:
var y = 1;
y = typeof x; // “undefined”
x = y; // “undefined”
#6: I think everyone sees that the function foo.bar is called by the nameless function. But it is called without the context of foo, so ‘this’ is actually the global context (window in browsers). So what is returned is typeof undefined, which equals ‘undefined’.
#7: Almost the same reasoning as in #6. You only need to be aware that the result of the assigment is merely the function foo.bar without its context.
#8: (n1, n2, … , nn) results in nn. I don’t particularly know why this is useful.
#11: Inside the function, foo is the argument foo, which equals { foo: { bar: 1 } }
So foo.bar does not exist. But foo.foo does, and so does foo.foo.bar
#12: Firstly, inside the global function f, the global function f cannot be accessed by its name anymore, since another f is declared inside the function too. Once you enter a scope (a function’s scope in this case), all function and variable declarations are handled before the rest of the code is run. In this case, f is declared twice before the return statement is run, so the moment that the return statement is run, f is the last declared function (and returns 2).
#13: ‘new’ returns an instance of the class, unless the function that defines the class returns something else that is an object. So in this case, new f() just returns the function f itself and not an instance of it.
===
I don’t get #9 myself. It has different results in different browsers. Plz enlighten us, Juriy.
Ben Cherry said:
#Andy: Awesome explanations.
Re #9: The function expression is given a name, “f”, but that does not make it a function declaration, so that name does not enter scope. The inclusion of that name is meant to confuse. Control enters the if statement because the expression is truthy, but there is no name “f” defined in scope, so typeof f === “undefined”. I think it’s clear why 1 + “undefined” === “1undefined”. I actually got this one wrong because for some reason I did 1 + “undefined” and came up with NaN in my head :(
skim said:
#@Andy Tjin: Thanks for answering #8. I also don’t understand how that would be useful. Basically anything before NN will be overridden by NN.
Andy Tjin said:
#@Ben:
Of course! This is an expression, not a declaration. Thanks for pointing it out. And now it’s also clear why it’s different in different browsers. In IE and FF, this actually *is* regarded as a declaration and therefore handled before the rest of the code is run.
Andrea Giammarchi said:
#@Andy #9 is considered a function expression so f won’t exists anywhere else but inside f body.
This would have produced the “1function”
var x = 1, F;
if (F = function f(){ /* f only here in ECMAScript 3rd */ }) {
x += typeof F;
}
x;
In few words the if statement with ( expression ) should explain itself by itself :D
I got trapped only by #2 replying too quickly but yes, IE will never fire that bloody Error polluting the current scope with that “g”
Nice one in any case, the most funny part has been my tweeted code to hack the form :P
Andrea Giammarchi said:
#just in case … still about #8
for(;function f(){};)/* typeof f === “undefined” */break;
while(function f(){})/* typeof f === “undefined” */break;
switch (function f(){}) {
default:alert(typeof f); // undefined
}
Function.prototype.loop = 1;
for(var k in function f(){})alert(typeof f); // undefined
Federico Lebrón said:
#Got #14 wrong, but not too annoyed by it. Using with would annoy me more than getting the question wrong ;)
Nice quiz!
caii said:
#“You’ve got 3 answers wrong (#4, #7, #9).
Very good, but not quite there yet.”
#7 is quiz!
I thought if :
var foo = {
bar: function(){alert(this); return this.baz; },
baz: 1
}
alert( typeof (foo.h = foo.bar)())
will be “number”;
but still show “undefined”;
Dan Dorman said:
#I missed numbers three, four, eight, and nine, and I didn’t even miss the latter for an interesting reason, just spaced the way Javascript concatenates strings. Three and four I got right on my second try. (undefined vs. “undefined”? Sheesh, kangax.) Eight was the only one I had literally no idea about–I’d never seen that syntax before, and I can’t imagine why it’d be useful. But it’s still nice to learn something new!
arnabc said:
#You’ve got 1 answer wrong (#9).
Very good, but not quite there yet. :-( … :-)
arnabc said:
#for #8 I got to test it in console, reading Zakas’s post earlier helped answer few questions,
also your post about http://yura.thinkweb2.com/named-function-expressions/ was useful for function expressions and #3 was explained in the “Delete operator” article published here couple of weeks back I guess, anyway it was truly a great exercise, thanks for all your effort Juriy :-)
Jani Hartikainen said:
#Wow, there’s some funny stuff there :D
I got 5 wrong, which I feel is a lot for me since I do consider myself to be pretty good with the language. I’m clearly not quite there yet, as the quiz said in the end!
However I must say I haven’t really seen almost any of this stuff in any real life solution. I do have to say that if you can answer all of these right without having to guess any *and* can explain why it works like that, you can call yourself a guru.
caii said:
#Wow, there’s some funny stuff there :D
a={
n:function(){alert(this.b)},
b:1
};
(a.m=a.n)(); //undefined why?
Christian C. Salvado said:
#I really enjoyed this quiz, and I would like to share my answers each with a brief description, maybe someone find them useful.
Any comments are appreciated.
Juriy, great job!
Andrea Giammarchi said:
#uhm, disappeared answer, still about statements and expressions:
for(;function f(){};) /* no f here */ break;while(function f(){}) /* no f here */ break;for(var k in function f(){}) /* no f here */ break;switch(function f(){}){default: typeof f; // undefined
};
The most interesting one is the ternary operator. If we omit the assignment, it generates an error, while if assign it, or it is an expression, it will be undefined:
var a = function f(){} ? typeof f : typeof f;This won’t work:
function f(){} ? typeof f : typeof f;While this will
(function f(){}) ? typeof f : typeof f;Regards
Asen Bozhilov said:
#@Andrea Giammarchi and what is the ineteresting in:
[code]function f(){} ? typeof f : typeof f;[/code] ?
12.4 Expression Statement
Note that an ExpressionStatement cannot start with an opening curly brace because that might make it ambiguous
with a Block. Also, an ExpressionStatement cannot start with the function keyword because that might make it
ambiguous with a FunctionDeclaration.
So here `function f(){}` is treat as a `FunctionDeclaration` and it’s absolutely expected behavior. SyntaxError.
Mariusz Nowak said:
#You’ve got 2 answers wrong (#12, #13).
12 is clear to me, I’ve just oversight ‘return’ within constructor somehow.. but 13th puzzled me for a while. I thought that when we’re talking about order of declarations and which one is actually used, function declaration would work similar as var assignment.. definitely too many “quirks” to handle ;)
Asen Bozhilov said:
#Can you ask anybody on the next questions:
function foo(bar) { return !bar; } (false) ? false : true;a) false
b) SyntaxError
c) true
(function foo(bar) { return !bar; } (false) ? false : true);a) SyntaxError
b) false
c) true
And of course please provide explanations.
qFox said:
#You’ve got 8 answers wrong (#1, #2, #3, #4, #6, #7, #9, #14).
That’s more than a half :(
Ahw :’(
Really got confused about named function expressions and their scope…
Very nice test.
Eugen said:
#Nice quiz, but I think that correct answer for question 9 is “1function” and not “1undefined”.
var x = 1; if (function f(){}) { x += typeof f; } x;Btw, got only 2 answers incorrect: #2 and #9
Paolo Chiodi said:
#6 wrong. if only I paid more attention, I would have made 3 less mistakes. bad
Abhishek said:
#You’ve got 1 answer wrong (#9).
Very good, but not quite there yet.
Sergei Morozov said:
#You’ve got 3 answers wrong (#2, #3, #9).
Very good, but not quite there yet.
Alan Adamik said:
#haha ! 10 wrong answers, a quick check on these wrong answers, and i got only 4 wrong after that.
Good Quizz :)
handy said:
#You’ve got 3 answers wrong (#5, #9, #11).
Very good, but not quite there yet.
Oh.. I think i must restudy javascript now~
agustinm said:
#Why #2 is “Error”???
Tim Down said:
##5 and #12 wrong, for the same reason each time: I misread the spec about the which how an identifier
is resolved inside a named function expression with name
and an argument called
. So close.
Alexandre Morgaut said:
#Eugen: about question #9
My first thinks were:
– “declaration are parsed first so f should exist”
– “What result should be returned when testing a declaration ?”
And then it clearly came up to me that the function f isn’t declared, there is no function f in the scope, the code is only testing a function expression (having its name property set to “f”), but as this expression isn’t affected to anything, it is dropped from memory.
Well I should directly have that it was an expression but I never saw unused and unaffected function as a condition in real code… I will remember as potential bug, but JSLint would never let it pass ;-)
Fredrik Holmström said:
#Got all but last correct, but that was probably a miss-click since I know that it returns 2 :). This test is really quite simple of you know the binding rules of typeof and instanceof. Also some answers till differ from browser to browser, since stuff like:
if(function f() {}) { }
Is handled subtlety different between browsers. All in all pretty useless, you won’t get all correct unless you’ve read the ECMA-262 spec a few times or worked on a JS implementation.
Radek Pech said:
#For question 2. is expected answer Error but running the code in IE returns “Number”.
And BTW this page itself does not work correctly in WebKit (Safari, Chrome, etc.) so tell us something about perfection…
Alexis said:
#question number nine seems to be false, according to the test, you should answer “1undefined”, however, i tried to execute this code thought firebug in firefox, and i got “1function”…
bobw said:
#I missed 2, 3, 6, 7, 8, and 9.
3 I was completely guessing on.
6 and 7 I just wasn’t paying attention.
2 and 9 I missed because I wasn’t thinking about them right…and I’m not sure I would have remembered correctly how they work regardless.
8 …Like several other people who have commented, I’d never seen that syntax, so it was a shot in the dark…and having had it explained, it makes even less sense to me.
Ian Ring said:
#dang, that was hard!
I got 7 wrong on the first try. Then going back through it all again very *carefully* I still had 4 wrong.
MaxiWheat said:
#Ow… 13 wrongs !!! I’m really bad at advanced javascript
fwg said:
#gosh, of all the answers that could go wrong, #11 is the one i fail.
damn, guess it was too obvious.
very nice quiz!
Alexandre Morgaut said:
#Alexis:
Firebug may return “1function” if “f” has already been created (by a previous code execution) in the scope as a function.
Try again replacing “f” with something you’re sure is not in memory (as “iamsureitsnotinmmemory”)
var x = 1;
if (function iamsureitsnotinmmemory(){}) {
x += typeof iamsureitsnotinmmemory;
}
x;
you should have “1undefined” with firebug ;-)
Jean said:
##2 #3 #5 #9 wrong
#2 – did not see the () after g, should have paid more attention
#3 – seldom use delete, so I had no clue
#5 – thought redefinition of f would be an Error, I would never use this construction, too confusing, bad practice
#9 – did not see that f would be anonymous, outside of its body, this is unrealistic
Very happy with my result since none of the above would really be a problem in the way I use JavaScript and I have never seen these in the real-world.
Thanks for the test.
Mickey said:
#Perhaps the questions could be numbered?
Most of these examples are so contrived, that it’s nice to be able to understand them as it would show you understand operator precedence, parsing order (hoisting) etc., but if someone I worked with did this any of this trying to be clever, I would shoot him or her immediately.
Dom said:
#Very nice test! Failed with 4 wrong responses.
I got also confused about named function expressions and their scope…
And I’m still dubious with the response for #9.
A+, Dom
Rick (rwaldron) said:
#So I finally had a chance to actually take the test, instead of just commenting on other people’s results.
You’ve got 1 answer wrong (#14).
Very good, but not quite there yet.
Kyle Simpson said:
#For those who keep asking about #9, this is the same reasoning as several other questions… the function f is not a declaration of a function, but a named function expression showing up inside an if-statement clause. Thus, for properly conforming browsers, the name “f” is not declared in the outer scope (although it unfortunately IS declared by IE). Therefore, it’s not available and typeof f == “undefined”. Interestingly, the name IS declared and available in the inner scope.
——
I’m a little confused by #4 still (though I got it right). Just recently I discovered that by spec, JS interprets an assignment operation left-to-right (so does PHP), as opposed to say the gcc compiler (c/c++, etc), which interprets assignment right-to-left (because of how values are computed and then stored in a register before being transfered to the lval location).
So, the fact that, clearly by spec, assignments should be left-to-right parsed/executed, and yet by evidence, the = assignment happens right to left in this example, is quite confusing.
To evidence that = does in fact go left-to-right in JS:
var a=[],i=0;
a[i++] = i;
alert(a[0]); // alerts 1, not 0
Try roughly that same thing in PHP, you’ll also get 1. Try it in c/c++ however, and you’ll get 0.
Here’s the spec reference for showing how assignment goes left-to-right:
ECMA Script 5th Edition, page 84, Section 11.3 “Assignment Operators” (thx @jdalton for ref!)
——
Now, my *educated guess* as to why #4 appears to go right-to-left is that in fact, because of operator precedence, the expression is interpreted as:
x = (y = typeof x)
as opposed to :
(x = y) = typeof x
If the former is in fact true, it’s quite obvious why “y” ends up as “undefined” and thus the same is then assigned to “x”. So, = still operates left-to-right by spec, but operator precedence causes chained assignments to each operate in a right-to-left fashion. It’s like “right-to-left” execution of several “left-to-right” assignment operations.
Also, it’s important to remember (which I frequently find myself reverting in my own mind) that “undefined” means “uninitialized”, not “undeclared”. So, “x” is clearly “declared” because of left-to-right, but “unitialized” (ie, “undefined”) because of operator precedence.
Peter Foti said:
##3 and #14 wrong (I never use delete or with).
I agree with what Fredrik Holmström said (http://perfectionkills.com/javascript-quiz/#comment-58151).
Unfortunately, I didn’t think this was a very good quiz because the examples are so convoluted and certainly do NOT represent anything I would expect to see in the real world. Also, as has already been pointed out, the results from these will differ depending on browser. I suppose that can be explained away as being an ECMAScript vs. a specific implementation, but again, in the real world developers have to be aware of browser implementations.
Lastly, in the intro was written:
“I wanted to keep question not very obscure”
FAIL. As I said, these examples do not represent anything I would expect to see in real world examples. Sure, you can do “typeof typeof x;”, but only an idiot would.
“Most of these are applied in practice quite often.”
Sorry, I disagree. Anyone who codes in a manner that “return typeof arguments” or defines a function f with 2 inner functions also named f needs to change professions. The examples in this quiz focus on rare edge case scenarios that certainly are NOT applied in practice quite often.
A good quiz for some of the OBSCURE uses of JavaScript, but not what I consider a good quiz for practical JavaScript.
Andrea Giammarchi said:
#@Asen Bozhilov … everything in this quiz is expected behavior, so nothing is interesting, accordingly with your reply … anyway ….
function foo(bar) { return !bar; } (false) ? false : true;named function declaration, ternary over the returned value, since the ternary is a not itself (true ? false : true) the answer is false: easy, expected behavior.
If you assign it becomes a named function expression.
Same result for the second one except that is a named function expression in any case, and for all non IE browsers, since IE will pollute the scope with foo function: easy, expected behavior.
If my ternary example was not interesting, your one is even boring …
Regards
Dimitar Milushev said:
#You’ve got 5 answers wrong (#2, #6, #7, #9, #13). It seems I have a lot to learn:)
Eneko Alonso said:
#Got 9 answers wrong! So much to learn, still.
By the way, I tested them in Firebug and #9 returns something unexpected, which is not in the answers of the question: “1number”. I have no idea how Firebug (FF3.6, FB1.6) has come up with that result.
Andrea Giammarchi said:
#@kangax please remove my comments, in any case I won’t go on with silly discussions. Keep writing good posts like this, thanks.
Asen Bozhilov said:
#@Andrea Giammarchi Actually no. First of all term “Named function declaration” is wrong. There only Function Declaration.
FunctionDeclaration :
function Identifier ( FormalParameterList ) { FunctionBody }
So you cannot type “Anonymous Function Declaration”, if you type:
function (){}
That will produce SyntaxError.
In my example, during the Variable Instantiation will be define property in AO/VO of current execution context with name `foo’, with attribute {DontDelete} and value, which refer created function object. If VO/AO has property with name `foo’, their value and attributes will be replace.
During execution of my function:
(false) ? false : true;That isn’t evaluate as a Function Calls expression. That will be evaluate to:
“Conditional Operator ( ?:)”
So the absolutely expected result is: `true’.
Regards.
Shuo Geng said:
#You’ve got 3 answers wrong (#3, #9, #13).
Very good, but not quite there yet.
Andrew Dodson said:
#You’ve got 8 answers wrong (#1, #2, #3, #7, #8, #9, #11, #14).
I didn’t even try #14, and #13 was a guess.
Its a test to read obfuscated code isn’t it!? A wank bank over the flexibility of Javascript!? Whatever it is my balls remain intact.
Jeremy Osborne said:
#Really nice quiz. I got 3, 9 and 14 wrong the first time, and when I worked through all of them I learned something new.
Thanks for posting this.
Awesome Bob said:
#You’ve got 0 answers wrong.
Flawless victory.
Awesome…
#14 Almost got me… OK I admit, I Googled it…
DirtyQwerty said:
#I can’t think of a use for this kind of code other than cryptic tests. If you ever put this kind of code in production I pity whoever has to maintain it.
Rick (rwaldron) said:
#@DirtyQwerty
The point is not to give you some kind of cut & paste snippet to drop into your program and magically do something…
The real point of the quiz is quite important, as it tests a JavaScript programmer’s real understanding of base concepts that are VERY MUCH applicable to real world production level code.
For example, I don’t want some idiot on my team trying to delete arguments with “delete x;” inside a function. I also don’t want to see people passing object literals as arguments and not referencing there properties within the correct context/scope.
This is VERY VERY real world.
Marcus Westin said:
#100% =P
var xhr = new (window.XMLHttpRequest || function() { return new ActiveXObject("Msxml2.XMLHTTP"); })()
xhr.open('GET', '/js/quiz.js', false);
xhr.send(null);
var answers = xhr.responseText.match(/byId\('.*'\)\.checked/g);
for (var i=0, answer; answer = answers[i]; i++) {
answer = answer.split('\'')[1]
document.getElementById(answer).checked = true;
}
Ben Cherry said:
#@Kyle, Re #4:
I don’t think it’s really about operator precedence, so much as semantics and lvalues.
Clearly, (x = y) is not an lvalue. Try `(x = y) = 1` in Firebug, you’ll get a syntax error.
Before the assignment happens, both the lvalue and the right-hand-side (RHS) need to be evaluated. It appears to evaluate the lvalue first, but that does not mean that assignment happens before the RHS has been evaluated.
In this case, the outer expression has lvalue ‘x’ and RHS ‘y = typeof x’. When the RHS is evaluated, we get an inner expression, with lvalue ‘y’ and RHS ‘typeof x’. These are both evaluated, then y is assigned to. Only then is x assigned to.
Also, of course both x and y will be “declared” long before any of this happens, because of hoisting.
El Honcho said:
#@Rick (rwaldron)
I agree with both you AND DirtyQwerty( what I think he was really driving at ). I got 12 out of 14 wrong. I’ve also been using javascript for over 5 years, quite effectively, for a lot of pretty heavy commercial work. Once tested, it’s all worked very well. What this test proves is that Javascript is a very deceptive language. It is simple, yet deeply convoluted, even to the point of being as flawed as it is powerful. It’s academically cool, sure, but it is also greatly reduced in its usefulness when you have to deal with the odd scoping, and it’s pseudo-OOP, pseudo-functional wackiness. The fact too, that despite having more tutorials and books about it than probably any other language, very few people “get it”. That seems a good indicator of a badly designed tool. Of course, some people will feel this is a feature, if only out of smug ego( no, I am not meaning YOU, ), with other’s admiring it as elegant expression. Me? Give me C#, Java, and Python. At least those have some degree of sanity to them.
Cheers
sebascabot said:
#I had to cheat with my favorite javascript interpreter beside to reach such a high score.
Maybe I should change job ;-)
Great test.
Could you add the number beside the question in order to easy the link between the number and the question when we get our score. Or even better, just add a link from our miss answer to the question.
Bye.
Andrea Giammarchi said:
#Juriy, if I can suggest few tests …
About “var”:
(function () { var A = null; function A() {} return A; })()1. null
2. function A() {}
3. depends on browser
About “arguments”:
(function (A) { var A = A; function A() {} return A; })(null)1. null
2. function A() {}
3. depends on browser
About “delayed function declaration”:
(function () { return A; if (true) { function A($true) {} } else { function A($false) {} } })()1. function A($true) {}
2. function A($false) {}
3. Error / depends on browser
Asen Bozhilov said:
#@Andrea Giammarchi
1) Durring “Variable Instantiation” first will be defined property of AO/VO of current execution context, with name “A” and value which refer function object. If property exist, will be replace it’s value and attributes depends from the type of code.
Variable Declaration is next step in “Variable Instantiation”, but if property exist, that declaration doesn’t change property value and internal attributes. Durring execution assignment expression in your 1) exaple, will be replace value of property of AO/VO with name `A’ with value `null’.
So the answer is: `null’.
2) After Variable Instantiation property with name `A’ of AO/VO will be refer function object. Assignment expression doesn’t change anything, and answer is: reference to `object’ which has [[Call]] and [[Construct]] method and [[Prototype]] property of this `object’ refer `object’ referred from `Function.prototype’.
3) Actually that is not very good question, because in ECMA 262 there are no FunctionStatement, and syntax grammer doesn’t allow FunctionDeclaration like this.
SourceElements: FunctionDeclaration FunctionBody : SourceElements: FunctionDeclarationSo the answer is SyntaxError. For implementation which support FunctionStatement, the answer is: ReferenceError. For buggy implementation like JScript which thread NFE and FunctionStatements as FunctionDeclaration the answer is:
function A($false) {}Regards.
Andrea Giammarchi said:
#@Marcus Westin … this is what I have tweeted yesterday :D
javascript:(function(O,K){for(;O<K.length;)document.getElementById("answer-"+ ++O+"-"+K[O-1]).checked=!0;})(0,[1,4,1,4,1,1,1,2,3,2,1,2,1,2])Rob said:
#Humbling indeed, Rick. I have alot of JavaScript to study…
JJP said:
#You’ve got 2 answers wrong (#11, #12).
Humbling experience
t= (function(foo){
return typeof foo.bar;
})({ foo: { bar: 1 } });
alert(t);
Andrew Dashin said:
#Could you please numerate questions. After the test it is quite hard to find questions which I’ve answered wrong.
Stefan said:
#Very, very nicely done.
I didn’t get them all right, which really irritated me.
Ah well, I guess you never stop learning :)
Looking forward to a sequel!
Charles Opute Odili said:
#Wow, what a test, You’ve got 10 answers wrong (#1, #2, #3, #4, #8, #9, #11, #12, #13, #14).
Peter said:
#I had 12 wrong, but then again, I hardly ever use JavaScript.
Anyway, are these based on real life code?
Peroli Sivaprakasam said:
#Wow… I got 13 correct.
You’ve got 1 answer wrong (#13).
Very good, but not quite there yet.
Ryan Cannon said:
#By the by, all of these questions other than #8 also work in ActionScript 3, if you turn off Strict Mode in Flash.
My personal favorite ECMA puzzler was
Number.prototype.isOne = function() { return this === 1; }; var x = 1; x.isOne()Bennett McElwee said:
#Thanks, this was wonderfully challenging. And yet somehow…
Only three wrong. Unbelievable.
#3: I was completely ignorant about the intricacies of the delete operator. Now I’m slightly less so.
#6: Missed the parentheses at the end of
arguments[0](). Coulda happened to anybody.#14: Didn’t know about functions.length. Probably still don’t. :)
Fascinating. JavaScript is definitely my favourite language ATM.
Chetan Sastry said:
#Got #2 and #12 wrong. Function expressions are confusing!
Wilson Lee said:
#I initially got half of the questions wrong, but after redoing the quiz and watching out for some very confounding parts everything seemed to make sense. Here is a post of explanations written afterwards.
Neil Rashbrook said:
#I got #2 and #9 wrong because I forgot that function expressions don’t declare top-level variables.
jerone said:
#Damn I really like this quiz. I’ve got 3 wrong, but after reading I understand all.
Some other interesting questions:
(function(){return 2*3;}).toString() === function () { return 6; };a) true
b) false
parseInt("12.5") === ~~"12.5";a) true
b) false
saraf uddin talukder said:
#You’ve got 0 answers wrong.
Flawless victory.
Dmitry A. Soshnikov said:
#Other suggestions (clear ECMAScript is taken, without augmentations, without non-standard features):
1. What will
1..zprovide:a) SyntaxError
b) New Range object (equivalent to new Range(1, ‘z’)) including all numbers and letters
c) undefined
d) Error of Range object (incompatible types for range: number and string)
e) ReferenceError “z” is not defined
1. What the result of
100['toString']['length']:a) 100
b) 3
c) 1
d) SyntaxError
P.S.: @kangax:
but I had to be attentive (and stop for a while to think) with some examples ;)
Dmitry A. Soshnikov said:
#@jerone:
Interesting question, but is not on ECMAScript; depends on implementation. In this current example sure will be false (as you compare result of toString and function object; just a typo? Did you want to use .toString too in the second function?), but if to use .toString() on both sides – it depends on implementation and is interesting example.
Yeah, the answer is in 11.4.8, ECMA-262-3, point (3), where ToInt32(…) is called. Twice bitwise NOT will return the result to the value on that point 3 ;) Also interesting example.
@Ryan Cannon:
Number.prototype.isOne = function() { return this === 1; }; var x = 1; x.isOne()Yes, primitive and object values are compared, so strict equal (in difference from equal: ==) will return false.
Dmitry A. Soshnikov said:
#One more:
a) true
b) false
c) depends on implementation
Charles said:
#Nice quiz. Good to remenber old questions
Jason LeBrun said:
#I missed #2 because I failed to notice the parens after the argument to typeof (careless reading).
I missed #13 because I simply rushed without thinking (careless reading).
I missed #14 because I didn’t know that the length property of a function returned the value of the arguments array. So, I’ve learned something new. :-)
Akzhan said:
#Heh, I did three mistakes.
Let me add new question about standard JavaScript library:
What is result of:
'the content here'.replace('content', '$$y $ $$ $$$');ECMAScript output is:
“the $y $ $ $$ here”
BTW, IE8 does not follow standard in this case.
https://bugzilla.mozilla.org/show_bug.cgi?id=531775
mk123456 said:
#как оказалось такой js я не знаю
всего 1 правильный ответ (ужас), пошел изучать!
Dmitry said:
#I’m programming for over 10 years in C, C++, C# and Java. Also use other languages occasionally and have used JavaScript many times too. But in this test I got only a couple right and in some cases I had no idea which answer to choose. What a weird language this JS is! I think when it’s allowed to create constructs that are so unclear and ambiguous something has to be done to that language design. Thanks for your efforts.
goodman said:
#You’ve got 9 answers wrong (#2, #3, #4, #6, #7, #8, #9, #10, #14).
That’s more than a half :(
Dzhax said:
#10 answers wrong?? f_ck..i am so stupid.. ((
quickredfox said:
#In question 9, Firefox 3.6, Firebug 1.5.0 gives me “1object” … reading some comments question 9 seems unstable ?
jerone said:
#@Dmitry A. Soshnikov
I meant to write:
(function(){return 2*3;}).toString() === (function(){return 6;}).toString();Peter said:
#Brilliant tests!
Thank you very-very much :)
I’ve got 3 answers wrong (#3, #5, #9).
Very good, but not quite there yet.
Chris Drost said:
#Here are the full answers/solutions to this quiz. :D
1. (function () { return typeof arguments; })(); Answer: "object".In Javascript, arguments is not a full-fledged array, but is merely an object. You must call Array.prototype.slice.call(arguments, 0) if you want to turn it into a full-fledged array.
2. var f = function g() { return 23; }; typeof g(); Answer: Error.The javascript keyword
functionhas two roles: it can be a statement, when it is the first thing on the line, or it can be an operator, when it appears in the middle of some other statement. When it is a statement, it does two special things: it floats toward the top of its codespace, and it assigns itself to a private variable in that space.Here, it is an operator. It creates a function which calls itself g, and assigns it to the variable name f. It’s important that you recognize that nobody else calls this function g; g is just its own private name for itself — it’s still fundamentally an anonymous function. Thus, the substatement
g()is a ReferenceError.3. (function (x) { delete x; return x; })(1); Answer: 1.You can’t delete function arguments, but trying to will not raise an error. Wherever possible, use undefined — delete should be reserved for removing keys from for-in iterators.
The assignment operator = is an operator. It is right-associative, and it evaluates to whatever was on its right. Thus, “a = b = c = a” is not a clever way to set (a,b,c) to (b,c,a), but rather it sets (a,b,c) to (a,a,a).
The var statement declares private variables in the local codespace, and the initialization of those variables happens after they’re fully declared. So this is really saying:
Thus, x and y both get set to
typeof undefined, which is “undefined”.5. (function f(f) { return typeof f(); })(function(){ return 1; }); Answer: "number".This function calls itself f — but it also calls its first argument f. Who wins? The argument does. ’nuff said.
6. var foo = { bar: function () { return this.baz; }, baz: 1 }; (function () { return typeof arguments[0](); })(foo.bar); Answer: "undefined".It’s important to understand that
thisis not a closure variable. Instead, it is determined at function-run-time, by the entity which it ‘belongs to’ at the time — and if there is no such object, then the object iswindow. So if you callfoo.bar(), thenthiswill point atfoo. But when you callarguments[0](), it points atargumentsinstead. Sincearguments.bazis undefined, you get this particular behaviour.7. var foo = { bar: function(){ return this.baz; }, baz: 1 }; typeof (f = foo.bar)(); Answer: "undefined".Since the assignment to global variable
fmakes this function not belong to any entity,thispoints towindowand the result is again “undefined” — unless you habitually set window.baz. :D8. var f = (function f() { return "1"; }, function g() { return 2; })(); typeof f; Answer: "number".The operator
,is like the keywordfunction— it has its fingers in many pies. Usually, commas are used as a syntactic element in var statements, function arguments, and object/array notations. But the humble comma is also an operator in its own right — a left-associative operator which returns the value on its right. (By virtue of being lower-precedence than =, comma is the lowest-precedence operator, as well.)As we now know, the g() syntax just establishes something which the function calls itself — but the function is anonymous to everyone else until assigned a variable. Thus, the second function here is selected by the comma, and it is immediately run. This makes the assignment equivalent to
var f = 2;.9. var x = 1; if (function f(){}) { x += typeof f; } x; Answer: "1undefined".They don’t actually let you answer the first thing that came to my mind, which was “ReferenceError.” It turns out that
typeof xdoesn’t generate ReferenceErrors when x is not a valid variable in the local codespace. In any case, the above comments about function operators not being function statements — and thus not defining a variablefin the local scope — causesfto be an invalid variable within that scope. Thus, its typeof is “undefined”.This is easier than it has to be: typeof always returns strings. Essentially, we’re asked to evaluate
typeof typeof typeof y— which, rather than throwing a ReferenceError, gives “string”.11. (function (foo) { return typeof foo.bar; })({ foo: { bar: 1 } }); Answer: "undefined".If the argument to the function were {bar: 1}, then this would return “number”. However, the argument is {foo: {bar: 1}}, and thus the
baron the root object is undefined.12. (function f() { function f() { return 1; } return f(); function f() { return 2; } })(); Answer: 2.The inner two usages of
functionare statements which begin with the keywordfunction— hence they are function statements, not function operators. Function statements float towards the top of their codespace. This is sometimes called “hoisting”. Unlike the var statement, which floats the variable declarations but not assignments toward the top of the codespace, the whole function body goes with it.13. function f(){ return f; } new f() instanceof f; Answer: false.When you return an object (other than null) or a function from a constructor, this return value overrides the constructor’s normal output. In this case, we have the egotistical function f, which always returns itself. Trying to construct an object via new f() will simply return f itself. Since new f() is not an object, then, it’s not an instance of anything.
(Actually, that’s a lie. Functions are secretly objects, and
f instanceof Functionevaluates to true. This also means that you could set, for example,f.foo = "bar"without impunity.)14. with (function (x, undefined) {}) { length; } Answer: 2.A function’s length is its number of expected (named) arguments.
The use of
undefinedhere is not actually a syntax error, becauseundefinedcan actually be redefined to a value other thanvoid(0). It is a valid token, if an unusual one.Dmitry A. Soshnikov said:
#Ok, one more quiz: http://dmitrysoshnikov.com/ecmascript/the-quiz/ ;)
Baltabek Bekenov said:
#=) You’ve got 6 answers wrong (#1, #2, #4, #7, #8, #9). Very good, but not quite there yet.
Fdream said:
#The answer of 9 in Chrome, Opera, Firefox, Safari is ‘1undefined’, in IE is ‘1function’, in firebug sometime is ‘1number’, I even thought this should throw a error but I was wrong.
slalx said:
#You’ve got 5 answers wrong (#2, #4, #8, #9, #11).
MarkS said:
#I thought I knew more – everything wrong except 1,2,4,5,9 (and 9 was lucky)
and I’ve been programming in Lisp for 25 years :-(
Javascript seems like it has some quirks… is this language design problem or a new kind of reasoning ?
tot2ivn said:
#I got 6 answers wrong #2, 3, 8, 9, 12, 13.
Thanks guys for the real fun quiz, and the answers.
Jonathan Azoff said:
#sweet quiz, here are my results:
“You’ve got 4 answers wrong (#2, #8, #9, #13).
Very good, but not quite there yet.”
Nothing like finding out stuff you didn’t know :)
Ethan B said:
#10/14 correct… and I’ve only been knee-deep in Javascript for about a month.
I’m feeling quite proud, ATM. :)
chengyoung said:
#You’ve got 8 answers wrong (#2, #4, #7, #9, #10, #11, #12, #13).
That’s more than a half :(
chapai said:
#technically quiz is crap – primitive questions with tricky mistakes.
also #2 is wrong
only #12 interesting.
Kragen Javier Sitaker said:
#“You’ve got 3 answers wrong (#3, #9, #14).” I expected to do better beforehand, but when I pressed the button, I was surprised I didn’t do worse!
Weixi Yen said:
#Tricky stuff, but everything makes sense. Great post.
Angus Croll said:
#You’ve got 4 answers wrong (#2, #7, #12, #13).
Annoyed at getting #12 wrong, can live with the others
php web developer said:
#I am php web developer, understand JavaScript, I will take this quiz later some time.
because it’s too late here already.
You provide in depth knowledge, keep this work up.
Cheers,
qammar