-
parseInt 遇上 map
["1", "2", "3"].map(parseInt); // A. ["1", "2", "3"] // B. [1, 2, 3] // C. [0, 1, 2] // D. other
答案 D,实际返回结果为[1, NaN, NaN],parseInt 需要两个参数 parse(value,radix),map 的回调函数需要三个参数 map(currentValue, index, array)。parseInt 的第二个参数是一个 2 到 36 之间的整数值,用于指定转换中采用的基数。如果该参数省略或为 0,则数字将以 10 作为基数来解析。如果该参数小于 0 或大于 36,则 parseInt 返回 NaN,转换失败也返回 NaN。parseInt(“1”, 0)的结果被当作十进制来解析,返回 1;parseInt(“2”, 1)的第二个参数小于 2,返回 NaN;parseInt(“3”, 2)在二进制中,“3”是非法字符,转换失败,返回 NaN。
-
愤怒的 reduce
[[3, 2, 1].reduce(Math.pow), [].reduce(Math.pow)]; // A. an error // B. [9, 0] // C. [9, NaN] // D. [9, undefined]
答案是 A,如果数组为空或没有 initialValue,会抛出 TypeError
-
死循环陷进
var END = Math.pow(2, 53); var START = END - 100; var count = 0; for (var i = START; i <= END; i++) { count++; } console.log(count); // A. 0 // B. 100 // C. 101 // D. other
答案是 D,在 js 中,2^53 是最大的值,没有比这更大的值了,所以 2^53 + 1 == 2^53,所以这个死循环无法终止。
-
过滤器魔法
var ary = [0, 1, 2]; ary[10] = 10; ary.filter(function (x) { return x === undefined; }); // A. [undefined x 7] // B. [0, 1, 2, 10] // C. [] // D. [undefined]
答案是 C,filter 中的 callback 函数只会在已赋值的索引上被调用,对于哪些已经被删除或从未被赋值的索引不会被调用。这道题中,array 实际是[0,1,2,undefined * 7, 10],所以这 7 个值为 undefined 的元素不会被 callback 调用,剩下的元素不满足 x === undefined 的条件,所以返回空数组。
-
数组原型是数组
Array.isArray(Array.prototype); // A. true // B. false // C. error // D. other
答案是 A,一个鲜为人知的事实:其实 Array.prototype 也是一个数组。这点在 MDN 文档中提到过。
-
一言难尽的强制转换
var a = [0]; if ([0]) { console.log(a == true); } else { console.log("wut"); } // A. true // B. false // C. "wut" // D. other
答案是 B。== 相等中,如果有一个操作数是布尔类型,会先把他转成数字,所以比较变成了 [0] == 1;同时规范指出如果其他类型和数字比较,会尝试把这个类型转成数字再进行宽松比较,而对象(数组也是对象)会先调用它的 toString() 方法,此时 [0] 会变成 “0”,然后将字符串 “0” 转成数字 0,而 0 == 1 的结果显然是 false。
-
撒旦之子“==”
[] == []; // A. true // B. false // C. error // D. other
答案是 B。ES5 规范指出:如果比较的两个对象指向的是同一个对象,就返回 true,否则就返回 false,显然,这是两个不同的数组对象。
-
加号“+”和减号“-”
"5" + 3; "5" - 3; // A. "53", 2 // B. 8, 2 // C. error // D. other
答案是 A。“5” + 2 = “52” 很好理解,+ 运算符中只要有一个是字符串,就会变成字符串拼接操作。你不知道的是,- 运算符要求两个操作数都是数字,如果不是,会强制转换成数字,所以结果就变成了 5 - 2 = 3。
-
统统算我的
function sidEffecting(ary) { ary[0] = ary[2]; // ary = [10, 1, 10] } function bar(a, b, c) { c = 10; sidEffecting(arguments); return a + b + c; } bar(1, 1, 1); // A. 3 // B. 12 // C. error // D. other
答案是 D。 实际上结果是 21。在 JavaScript 中,参数变量和 arguments 是双向绑定的。改变参数变量,arguments 中的值会立即改变;而改变 arguments 中的值,参数变量也会对应改变。
-
反转世界
var x = [].reverse; x(); // A. [] // B. undefined // C. error // D. window
答案是 D。 MDN 规范关于 reverse 的描述: reverse 方法颠倒数组中元素的位置,并返回该数组的引用。而这里调用的时候没有制定数组,所以默认的 this 就是 window,所以最后结果返回的是 window。
-
自动提升为全局变量
(function () { var x = (y = 1); })(); console.log(y); console.log(x); // A. 1, 1 // B. error, error // C. 1, error // D. other
答案是 C。 在函数中没有用 var 声明变量 y,所以 y 会被自动创建在全局变量 window 下面,所以在函数外面也可以访问得到。而 x 由于被 var 声明过,所以在函数外部是无法访问的。
-
禁止修改函数名
function foo() {} var oldName = foo.name; foo.name = "bar"; [oldName, foo.name]; // A. error // B. ["", ""] // C. ["foo", "foo"] // D. ["foo", "bar"]
答案是 C。 函数名是禁止修改的,规范写的很清楚,所以这里的修改无效。
-
逗号定义数组
[, , ,].join(", "); // A. ", , , " // B. "undefined, undefined, undefined, undefined" // C. ", , " // D. ""
答案是 C。 JavaScript 允许用逗号来定义数组,得到的数组是含有 3 个 undefined 值的数组。MDN 关于 join 方法的描述:所有的数组元素被转换成字符串,再用一个分隔符将这些字符串连接起来。如果元素是 undefined 或者 null, 则会转化成空字符串。
-
保留字 class
var a = { class: "Animal", name: "Fido" }; console.log(a.class); // A. "Animal" // B. Object // C. an error // D. other
答案是 D。 实际上真正的答案取决于浏览器。class 是保留字,但是在 Chrome、Firefox 和 Opera 中可以作为属性名称,在 IE 中是禁止的。另一方面,其实所有浏览器基本接受大部分的关键字(如:int、private、throws 等)作为变量名,而 class 是禁止的。
-
神鬼莫测的函数长度
var a = Function.length; var b = new Function().length; console.log(a === b); // A. true // B. false // C. error // D. other
答案是 B。 实际上 a 的值是 1,b 的值是 0。
Function 构造器的属性:
Function 构造器本身也是个 Function。他的 length 属性值为 1 。该属性 Writable: false, Enumerable: false, Configurable: true。
Function 原型对象的属性:
Function 原型对象的 length 属性值为 0 。
-
Date 的面具
var a = Date(0); var b = new Date(0); var c = new Date(); [a === b, b === c, a === c]; // A. [true, true, true] // B. [false, false, false] // C. [false, true, false] // D. [true, false, false]
答案是 B。 需要注意的是只能通过调用 Date 构造函数来实例化日期对象:以常规函数调用它(即不加 new 操作符)将会返回一个字符串,而不是一个日期对象。另外,不像其他 JavaScript 类型,Date 对象没有字面量格式。所以 a 是字符串,b 和 c 是 Date 对象,并且 b 代表的是 1970 年那个初始化时间,而 c 代表的是当前时间。
-
mix 和 min
var min = Math.min(); var max = Math.max(); console.log(min < max); // A. true // B. false // C. error // D. other
答案是 B。 对 Math.min,如果没有参数,结果为 Infinity。对 Math.max,如果没有参数,结果为-Infinity。
-
重复声明变量
function foo(a) { var a; return a; } function bar(a) { var a = "bye"; return a; } [foo("hello"), bar("hello")]; // A. ["hello", "hello"] // B. ["hello", "bye"] // C. ["bye", "bye"] // D. other
答案是 B。 一个变量在同一作用域中已经声明过,会自动移除 var 声明,但是赋值操作依旧保留,结合前面提到的变量提升机制。