JavaScript Puzzlers!

JavaScript Puzzlers!

or: do you really know JavaScript?

(or: how insane do you think JavaScript actually is?)

let’s start

下面是我做题后的一个总结和归纳(可能解释不是很标准)

1

1
2
What is the result of this expression? (or multiple ones)
["1", "2", "3"].map(parseInt)

what you actually get is [1, NaN, NaN] because parseInt takes two parameters (val, radix) and map passes 3 (element, index, array)

2

1
2
What is the result of this expression? (or multiple ones)
[typeof null, null instanceof Object]

答案: [“object”, false]
因为历史遗留问题,typeof null 返回object.
instanceof运算符可以用来判断某个构造函数的prototype属性所指向的對象是否存在于另外一个要检测对象的原型链上。
我们可以通过obj.proto 来进行修改 (自己写的对象
null 是没有prototype 的属性

3

1
2
What is the result of this expression? (or multiple ones)
[ [3,2,1].reduce(Math.pow), [].reduce(Math.pow) ]

答案: 9, error (当然,会直接报错..)
reduce() 方法接收一个函数作为累加器(accumulator),数组中的每个值(从左到右)开始合并,最终为一个值。
该方法的参数是一个callback, 一个[作为第一次调用callback的参数],
如果arr为空,则直接报错,TypeError
另: reduce可用于数组求和,数组扁平化等.

4

1
2
3
What is the result of this expression? (or multiple ones)
var val = 'smtg';
console.log('Value is ' + (val === 'smtg') ? 'Something' : 'Nothing');

答案: Something
+ 的优先级要高,所以来不及三目运算, 前面这段就相当于一个变量, 所以在计算三目的时候,返回’Something’

5

1
2
3
4
5
6
7
8
9
10
What is the result of this expression? (or multiple ones)
var name = 'World!';
(function () {
if (typeof name === 'undefined') {
var name = 'Jack';
console.log('Goodbye ' + name);
} else {
console.log('Hello ' + name);
}
})();

答案: Goodbye Jack
变量提升,所以在第一句的if时, name 是为undefined,直到var name 才被定义

6

1
2
3
4
5
6
7
8
What is the result of this expression? (or multiple ones)
var END = Math.pow(2, 53);
var START = END - 100;
var count = 0;
for (var i = START; i <= END; i++) {
count++;
}
console.log(count);

别直接在控制台跑这段代码(别问我为什么直到 - -$)
摘自 ruanyifeng(链接)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
根据国际标准IEEE 754,JavaScript浮点数的64个二进制位,从最左边开始,是这样组成的。

1位:符号位,0表示正数,1表示负数
2位到第12位:储存指数部分
13位到第64位:储存小数部分(即有效数字)
符号位决定了一个数的正负,指数部分决定了数值的大小,小数部分决定了数值的精度。

IEEE 754规定,有效数字第一位默认总是1,不保存在64位浮点数之中。也就是说,有效数字总是1.xx...xx的形式,其中xx..xx的部分保存在64位浮点数之中,最长可能为52位。因此,JavaScript提供的有效数字最长为53个二进制位。

(-1)^符号位 * 1.xx...xx * 2^指数位
上面公式是一个数在JavaScript内部实际的表现形式。

精度最多只能到53个二进制位,这意味着,绝对值小于253次方的整数,即-(2^53-1)到2^53-1,都可以精确表示。

Math.pow(2, 53)
// 9007199254740992

Math.pow(2, 53) + 1
// 9007199254740992

Math.pow(2, 53) + 2
// 9007199254740994

Math.pow(2, 53) + 3
// 9007199254740996

Math.pow(2, 53) + 4
// 9007199254740996
从上面示例可以看到,大于253次方以后,整数运算的结果开始出现错误。所以,大于等于253次方的数值,都无法保持精度。

Math.pow(2, 53)
// 9007199254740992

// 多出的三个有效数字,将无法保存
9007199254740992111
// 9007199254740992000
上面示例表明,大于253次方以后,多出来的有效数字(最后三位的111)都会无法保存,变成0

7

1
2
3
4
What is the result of this expression? (or multiple ones)
var ary = [0,1,2];
ary[10] = 10;
ary.filter(function(x) { return x === undefined;});

答案: []
filter() 方法使用指定的函数测试所有元素,并创建一个包含所有通过测试的元素的新数组。
即所谓的过滤函数.
执行到第二句的时候 , ary = [0, 1, 2, undefined * 7, 10]
Array.prototype.filter is not invoked for the missing elements
另:

1
2
3
4
var ary = [0,1,2, undefined];
ary[10] = 10;
ary.filter(function(x) { return x === undefined;});
// --> [undefined]

8

1
2
3
4
5
6
What is the result of this expression? (or multiple ones)
var two = 0.2
var one = 0.1
var eight = 0.8
var six = 0.6
[two - one == one, eight - six == two]

9

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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'));

答案: Do not know!
switch uses === internally and new String(x) !== x

10

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
What is the result of this expression? (or multiple ones)
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
String(x) does not create an object but does return a string, i.e. typeof String(1) === “string”

11

1
2
3
4
5
6
7
8
9
10
11
12
What is the result of this expression? (or multiple ones)
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, false, false]
Infinity % 2 gives NaN, -9 % 2 gives -1 (modulo operator keeps sign so it’s result is only reliable compared to 0)

12

1
2
3
4
5
What is the result of this expression? (or multiple ones)

parseInt(3, 8)
parseInt(3, 2)
parseInt(3, 0)

答案: 3, NaN, 3

13

1
2
'5' + 3
'5' - 3

答案: “53”, 2
javascript 的隐式转换,

14

1
2
What is the result of this expression? (or multiple ones)
1 + - + + + - + 1

答案: 2

15

1
2
3
4
What is the result of this expression? (or multiple ones)
var ary = Array(3);
ary[0]=2
ary.map(function(elem) { return '1'; });

答案: [“1”, undefined × 2]
上面提到过,对为初始化的不起作用

16

1
2
3
4
5
6
7
8
9
10
What is the result of this expression? (or multiple ones)
function sidEffecting(ary) {
ary[0] = ary[2];
}
function bar(a,b,c) {
c = 10;
sidEffecting(arguments);
return a + b + c;
}
bar(1,1,1)

答案: 21
arguments 对象并不是一个真正的Array。它类似于数组,但没有数组所特有的属性和方法,除了 length.
in javascript variables are tied to the arguments object so changing the variables changes arguments and changing arguments changes the local variables even when they are not in the same scope.
在js中,变量和arguments 是绑定在一起的,所以改变了变量就是改变了arguments,改变了arguments 改变了当前的变量 ,及时不是在相同的作用域内.

17

1
2
3
4
What is the result of this expression? (or multiple ones)
var a = 111111111111111110000,
b = 1111;
a + b;

同 第六题

18

1
2
3
What is the result of this expression? (or multiple ones)
var x = [].reverse;
x();

答案: VM1357:2 Uncaught TypeError: Array.prototype.reverse called on null or undefined(…)
暂时不知道怎么解释.

19

1
Number.MIN_VALUE > 0

答案: false

在调试工具中为 5e-324, Number.MIN_VALUE 是最小的大于0的数

20

1
2
What is the result of this expression? (or multiple ones)
[1 < 2 < 3, 3 < 2 < 1]

答案: [true, true]

相同运算符优先级相等,故原来的式子相当于 [(1 < 2) < 3, (3 < 2) < 1]
其中存在隐式转换 true -> 1, false -> 0

21

1
2
3
What is the result of this expression? (or multiple ones)
// the most classic wtf
2 == [[[2]]]

答案: true
如果我们这样赋值 var a = [[[2]]] 相当于 a[0][0] = [2] a[0][0][0] = 2
== 比较的是值 ,故返回 true

22

1
2
3
4
What is the result of this expression? (or multiple ones)
3.toString()
3..toString()
3...toString()

答案: error, “3”, error

摘自stackoverflow: That is because when JavaScript sees a period after an integer, it assumes the value after it will be its decimals. Because of that, simply using 5.toString() will make JavaScript find toString where it expected numbers.
当javascript遇到整数后面带有小数点,为认为后面的是这个数的小数部分,所以3.toString() 当然 当申明一个变量a,赋值为3的时候,a.toString() 是可行的

23

1
2
3
4
5
6
What is the result of this expression? (or multiple ones)
(function(){
var x = y = 1;
})();
console.log(y);
console.log(x);

答案: 1, error

这题在考作用域的时候经常考到, var x = y = 1; 相当于 y = 1; var x = y; 所以在这里y 是全局变量,而x只在这个函数里面,
所以log(y) 为 1, x 就是is not defined

24

1
2
3
4
5
What is the result of this expression? (or multiple ones)
var a = /123/,
b = /123/;
a == b
a === b

答案: false, false

a,b 是正则表达式, 我们使用typeof 会发现它们都是object

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
摘自网络:
先说 ===,这个比较简单。下面的规则用来判断两个值是否===相等:
1、如果类型不同,就[不相等]
2、如果两个都是数值,并且是同一个值,那么[相等];(!例外)的是,如果其中至少一个是NaN,那么[不相等]。(判断一个值是否是NaN,只能用isNaN()来判断)
3、如果两个都是字符串,每个位置的字符都一样,那么[相等];否则[不相等]。
4、如果两个值都是true,或者都是false,那么[相等]。
5、如果两个值都引用同一个对象或函数,那么[相等];否则[不相等]。
6、如果两个值都是null,或者都是undefined,那么[相等]。
再说 ==,根据以下规则:
1、如果两个值类型相同,进行 === 比较。
2、如果两个值类型不同,他们可能相等。根据下面规则进行类型转换再比较:
a、如果一个是null、一个是undefined,那么[相等]。
b、如果一个是字符串,一个是数值,把字符串转换成数值再进行比较。
c、如果任一值是 true,把它转换成 1 再比较;如果任一值是 false,把它转换成 0 再比较。
d、如果一个是对象,另一个是数值或字符串,把对象转换成基础类型的值再比较。对象转换成基础类型,利用它的toString或者valueOf方法。 js核心内置类,会尝试valueOf先于toString;例外的是DateDate利用的是toString转换。非js核心的对象,令说(比较麻 烦,我也不大懂)
e、任何其他组合,都[不相等]。

25

1
2
3
4
5
6
7
8
What is the result of this expression? (or multiple ones)
var a = [1, 2, 3],
b = [1, 2, 3],
c = [1, 2, 4]
a == b
a === b
a > c
a < c

答案: false, false, false, true

解释同上, 数组在比较的时候,是按照字典序比较的, 故第四条的值为true,
另: 只要一次分出大小,直接返回结果,不看数组的大小,比如:

1
2
3
var a = [3];
var b = [1, 2];
a > b // log true

26

1
2
3
What is the result of this expression? (or multiple ones)
var a = {}, b = Object.prototype;
[a.prototype === b, Object.getPrototypeOf(a) === b]

答案: [false, true]
Object.getPrototypeOf() 方法返回指定对象的原型(也就是该对象内部属性[[Prototype]]的值)。
a 是一个Object, Object中 除了Functions有prototype属性之外都没有, 所以 a.prototype = undefined;
Every Object instead has an internal property accessible via Object.getPrototypeOf

27

1
2
3
4
What is the result of this expression? (or multiple ones)
function f() {}
var a = f.prototype, b = Object.getPrototypeOf(f);
a === b

答案: false
f.prototype is the object that will become the parent of any objects created with new f while Object.getPrototypeOf returns the parent in the inheritance hierarchy.
在控制台中,a 是一个Object, b 是一个 function

28

1
2
3
4
5
What is the result of this expression? (or multiple ones)
function foo() { }
var oldName = foo.name;
foo.name = "bar";
[oldName, foo.name]

答案: [“foo”, “foo”]
function.name 返回函数的名称.
Writable no
Enumerable no
Configurable yes
Note that in non-standard, pre-ES6 implementations the configurable attribute was false as well.
另: 当函数使用new Function(…) 或者 直接Function(…) 来创建的时候,其name属性为””, 如:

1
2
3
4
5
6
7
var f = function() {};
var object = {
someMethod: function() {}
};

console.log(f.name == ''); // true
console.log(object.someMethod.name == ''); // also true

( 更多)

29

1
2
What is the result of this expression? (or multiple ones)
"1 2 3".replace(/\d/g, parseInt)

答案: “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].

replace() 方法使用一个替换值(replacement)替换掉一个匹配模式(pattern)在原字符串中某些或所有的匹配项,并返回替换后的字符串。这个替换模式可以是字符串或者RegExp(正则表达式),替换值可以是一个字符串或者一个函数。
str.replace(regexp|substr, newSubStr|function[, flags])

1
2
3
4
5
6
7
8
9
参数
regexp
一个 RegExp 对象。该正则所匹配的内容会被第二个参数的返回值替换掉。
substr
一个要被 newSubStr 替换的字符串。
newSubStr
替换掉第一个参数在原字符串中的匹配部分。该字符串中可以内插一些特殊的变量名。
function
一个用来创建新子字符串的函数,该函数的返回值将替换掉第一个参数匹配到的结果。该函数的参数描述请参考 指定一个函数作为参数 小节。

另:

1
2
"1 'av' 3".replace(/\d/g,1) //-->"1 'av' 1"
"1 2 3".replace(/\d/g,1) //--> "1 1 1"

( 更多)

30

1
2
3
4
5
6
7
What is the result of this expression? (or multiple ones)
function f() {}
var parent = Object.getPrototypeOf(f);
f.name // ?
parent.name // ?
typeof eval(f.name) // ?
typeof eval(parent.name) // ?

答案: “f”, “Empty”, “function”, error
The function prototype object is defined somewhere, has a name, can be invoked, but it’s not in the current scope.

31

1
2
3
What is the result of this expression? (or multiple ones)
var lowerCaseOnly = /^[a-z]+$/;
[lowerCaseOnly.test(null), lowerCaseOnly.test()]

答案: [true, true]
该正则的意思就是符合所有的都是小写
而在函数test中,对于argument存在一个ToString的操作
故原来的式子等价于 .test(‘null’) , .test(‘undefined’)

32

1
2
What is the result of this expression? (or multiple ones)
[,,,].join(", ")

答案: “, , “
join() 方法将数组中的所有元素连接成一个字符串。
原来的数组相当于 [udefined * 3],join(“, “) –> “, , “

33

1
2
3
What is the result of this expression? (or multiple ones)
var a = {class: "Animal", name: 'Fido'};
a.class

答案: (浏览器)
class 是保留字,当在Chrome, Firefox, Opera中的时候,可以被认可,返回Animal, 在IE中的时候..

34

1
2
What is the result of this expression? (or multiple ones)
var a = new Date("epoch")

答案: Invalid Date
Date的四中构造方法, 详见 ()

35

1
2
3
4
What is the result of this expression? (or multiple ones)
var a = Function.length,
b = new Function().length
a === b

答案: flase
It’s false. Function.length is defined to be 1. On the other hand, the length property of the Function prototype object is defined to be 0.

36

1
2
3
4
var a = Date(0);
var b = new Date(0);
var c = new Date();
[a === b, b === c, a === c]

答案: [false, false, false]
a是字符串,b, c 是Object, 在===操作符面前,不用任何考虑,直接都是false

37

1
2
3
What is the result of this expression? (or multiple ones)
var min = Math.min(), max = Math.max()
min < max

答案: false
Math.min() 返回Infinity, 是javascript的全局对象,代表正的无穷大
Math.max() 返回-Infinity 所以…

38

1
2
3
4
5
6
7
8
9
10
11
12
What is the result of this expression? (or multiple ones)
function captureOne(re, str) {
var match = re.exec(str);
return match && match[1];
}
var numRe = /num=(\d+)/ig,
wordRe = /word=(\w+)/i,
a1 = captureOne(numRe, "num=1"),
a2 = captureOne(wordRe, "word=1"),
a3 = captureOne(numRe, "NUM=2"),
a4 = captureOne(wordRe, "WORD=2");
[a1 === a2, a3 === a4]

答案: [true, false]
Regular expressions in JavaScript if defined using the /g flag will carry a state across matches, even if they are actually used on different strings (the lastIndex property). This means a3 will be null as the regular expression was applied starting from the index of the last matched string, even if it was a different one.

39

1
2
3
4
What is the result of this expression? (or multiple ones)
var a = new Date("2014-03-19"),
b = new Date(2014, 03, 19);
[a.getDay() === b.getDay(), a.getMonth() === b.getMonth()]

答案: [fasle, false]
注意b 的构造方法 月份从0开始算,
所以a 返回 Wed Mar 19 2014 08:00:00 GMT+0800 (CST)
b 返回 Sat Apr 19 2014 00:00:00 GMT+0800 (CST)
然后getDay 是返回一个星期中的第几天(从0开始)(这有时候会是个坑)
要想返回一个月中的第几天,请使用getDate

40

1
2
3
4
5
6
What is the result of this expression? (or multiple ones)
if ('http://giftwrapped.com/picture.jpg'.match('.gif')) {
'a gif file'
} else {
'not a gif file'
}

答案: a gif file
传入的不是一个正则表达式对象,所以会隐式转换成一个正则表达式对象, .gif –> /.gif/
匹配的字符串为[“/gif”]

41

1
2
3
4
5
6
7
8
9
10
What is the result of this expression? (or multiple ones)
function foo(a) {
var a;
return a;
}
function bar(a) {
var a = 'bye';
return a;
}
[foo('hello'), bar('hello')]

答案:[“hello”, “bye”]
Variabled declarations are hoisted, but in this case since the variable exists already in the scope, they are removed altogether. In bar() the variable declaration is removed but the assignment remains, so it has effect.

小结

这是一套满满都是坑的题目,可能有些认为是钻牛角尖,但也是在开发过程中不能忽视的问题吧..