原文:http://javascript-puzzlers.herokuapp.com/
Javascript环境: 浏览器标准 ECMA 262 (5.1)
运行结果可能跟node 或者jsc REPL中有所不同。 比如 this
和 global
在 firefox console, node repl 和jsc shell 是不一样的。
绿色部分是正确答案。
["1", "2", "3"].map(parseInt)
["1", "2", "3"]
[1, 2, 3]
[0, 1, 2]
other
what you actually get is [1, NaN, NaN]
because parseInt
takes two parameters (val, radix) and map
passes 3(element, index, array)
[typeof null, null instanceof Object]
["object", false]
[null, false]
["object", true]
other
typeof
will always return "object" for native non callable objects.
[ [3,2,1].reduce(Math.pow), [].reduce(Math.pow) ]
an error
[9, 0]
[9, NaN]
[9, undefined]
Per spec: reduce on an empty array without an initial value throws TypeError
var val = 'smtg';console.log('Value is ' + (val === 'smtg') ? 'Something' : 'Nothing');
Value is Something
Value is Nothing
NaN
other
it actually prints 'Something
' the +
operator has higher precedence than the ternary one.
var name = 'World!';(function () { if (typeof name === 'undefined') { var name = 'Jack'; console.log('Goodbye ' + name); } else { console.log('Hello ' + name); }})();
Goodbye Jack
Hello Jack
Hello undefined
Hello World
The var
declaration is hoisted to the function scope, but the initialization is not.
var END = Math.pow(2, 53);var START = END - 100;var count = 0;for (var i = START; i <= END; i++) { count++;}console.log(count);
0
100
101
other
it goes into an infinite loop, 2^53 is the highest possible number in javascript, and 2^53+1 gives 2^53, so i
can never become larger than that.
var ary = [0,1,2];ary[10] = 10;ary.filter(function(x) { return x === undefined;});
[undefined × 7]
[0, 1, 2, 10]
[]
[undefined]
Array.prototype.filter
is not invoked for the missing elements.
var two = 0.2 var one = 0.1 var eight = 0.8 var six = 0.6[two - one == one, eight - six == two]
[true, true]
[false, false]
[true, false]
other
JavaScript does not have precision math, even though sometimes it works correctly.
function showCase(value) { switch(value) { case 'A': console.log('Case A'); break; case 'B': console.log('Case B'); break; case undefined: console.log('undefined'); break; default: console.log('Do not know!'); }}showCase(new String('A'));
Case A
Case B
Do not know!
undefined
switch
uses ===
internally and new String(x) !== x
function showCase2(value) { switch(value) { case 'A': console.log('Case A'); break; case 'B': console.log('Case B'); break; case undefined: console.log('undefined'); break; default: console.log('Do not know!'); }}showCase2(String('A'));
Case A
Case B
Do not know!
undefined
String(x)
does not create an object but does return a string, i.e. typeof String(1) === "string"
function isOdd(num) { return num % 2 == 1;}function isEven(num) { return num % 2 == 0;}function isSane(num) { return isEven(num) || isOdd(num);}var values = [7, 4, '13', -9, Infinity];values.map(isSane);
[true, true, true, true, true]
[true, true, true, true, false]
[true, true, true, false, false]
[true, true, false, false, false]
Infinity % 2
gives NaN
, -9 % 2
gives -1
(modulo operator keeps sign so it's result is only reliable compared to 0)
parseInt(3, 8)parseInt(3, 2)parseInt(3, 0)
3, 3, 3
3, 3, NaN
3, NaN, NaN
other
3
doesn't exist in base 2
, so obviously that's a NaN
, but what about 0
? parseInt
will consider a bogus radix and assume you meant 10
, so it returns 3
.
Array.isArray( Array.prototype )
true
false
error
other
Array.prototype
is an Array
. Go figure.
var a = [0];if ([0]) { console.log(a == true);} else { console.log("wut");}
true
false
"wut"
other
[0]
as a boolean is considered true
. Alas, when using it in the comparisons it gets converted in a different way and all goes to hell.
[]==[]
true
false
error
other
==
is the spawn of satan.
'5' + 3 '5' - 3
"53", 2
8, 2
error
other
Strings know about +
and will use it, but they are ignorant of -
so in that case the strings get converted to numbers.
1 + - + + + - + 1
2
1
error
other
Great fun.
var ary = Array(3);ary[0]=2ary.map(function(elem) { return '1'; });
[2, 1, 1]
["1", "1", "1"]
[2, "1", "1"]
other
The result is ["1", undefined × 2]
, as map
is only invoked for elements of the Array
which have been initialized.
function sidEffecting(ary) { ary[0] = ary[2];}function bar(a,b,c) { c = 10 sidEffecting(arguments); return a + b + c;}bar(1,1,1)
3
12
error
other
The result is 21
, in javascript variables are tied to the arguments
object so changing the variables changesarguments
and changing arguments changes the local variables even when they are not in the same scope.
var a = 111111111111111110000, b = 1111;a + b;
111111111111111111111
111111111111111110000
NaN
Infinity
Lack of precision for numbers in JavaScript affects both small and big numbers.
var x = [].reverse;x();
[]
undefined
error
window
[].reverse
will return this
and when invoked without an explicit receiver object it will default to the defaultthis
AKA window
Number.MIN_VALUE > 0
false
true
error
other
Number.MIN_VALUE
is the smallest value bigger than zero, -Number.MAX_VALUE
gets you a reference to something like the most negative number.
[1 < 2 < 3, 3 < 2 < 1]
[true, true]
[true, false]
error
other
Implicit conversions at work. both true
and false
are greater than any number.
2 == [[[2]]]
true
false
undefined
other
both objects get converted to strings and in both cases the resulting string is "2"
3.toString() 3..toString() 3...toString()
"3", error, error
"3", "3.0", error
error, "3", error
other
3.x
is a valid syntax to define "3" with a mantissa of x
, toString
is not a valid number, but the empty string is.
(function(){ var x = y = 1;})();console.log(y);console.log(x);
1, 1
error, error
1, error
other
y
is an automatic global, not a function local one.
var a = /123/, b = /123/;a == ba === b
true, true
true, false
false, false
other
Per spec Two regular expression literals in a program evaluate to regular expression objects that never compare as === to each other even if the two literals' contents are identical.
var a = [1, 2, 3], b = [1, 2, 3], c = [1, 2, 4]a == ba === ba > ca < c
false, false, false, true
false, false, false, false
true, true, false, true
other
Arrays are compared lexicographically with >
and <
, but not with ==
and ===
var a = {}, b = Object.prototype;[a.prototype === b, Object.getPrototypeOf(a) === b]
[false, true]
[true, true]
[false, false]
other
Functions have a prototype
property but other objects don't so a.prototype
is undefined
.
Every Object
instead has an internal property accessible via Object.getPrototypeOf
function f() {}var a = f.prototype, b = Object.getPrototypeOf(f);a === b
true
false
null
other
f.prototype
is the object that will become the parent of any objects created with new f
whileObject.getPrototypeOf
returns the parent in the inheritance hierarchy.
function foo() { }var oldName = foo.name;foo.name = "bar";[oldName, foo.name]
error
["", ""]
["foo", "foo"]
["foo", "bar"]
name
is a read only property. Why it doesn't throw an error when assigned, I do not know.
"1 2 3".replace(/\d/g, parseInt)
"1 2 3"
"0 1 2"
"NaN 2 3"
"1 NaN 3"
String.prototype.replace
invokes the callback function with multiple arguments where the first is the match, then there is one argument for each capturing group, then there is the offset of the matched substring and finally the original string itself. so parseInt
will be invoked with arguments 1, 0
, 2, 2
, 3, 4
.
function f() {}var parent = Object.getPrototypeOf(f);f.name // ?parent.name // ?typeof eval(f.name) // ?typeof eval(parent.name) // ?
"f", "Empty", "function", "function"
"f", undefined, "function", error
"f", "Empty", "function", error
other
The function prototype object is defined somewhere, has a name, can be invoked, but it's not in the current scope.
var lowerCaseOnly = /^[a-z]+$/;[lowerCaseOnly.test(null), lowerCaseOnly.test()]
[true, false]
error
[true, true]
[false, true]
the argument is converted to a string with the abstract ToString
operation, so it is "null"
and "undefined"
.
[,,,].join(", ")
", , , "
"undefined, undefined, undefined, undefined"
", , "
""
JavaScript allows a trailing comma when defining arrays, so that turns out to be an array of three undefined.
var a = {class: "Animal", name: 'Fido'};a.class
"Animal"
Object
an error
other
The answer is: it depends on the browser. class
is a reserved word, but it is accepted as a property name by Chrome, Firefox and Opera. It will fail in IE. On the other hand, everybody will accept most other reserved words (int
, private
, throws
etc) as variable names too, while class
is verboten.