你不知道的Javascript “谜题”
["1", "2", "3"].map(parseInt)
A. ["1", "2", "3"]
B. [1, 2, 3]
C. [0, 1, 2]
D. other
解析:D
map接受两个参数,一个回调函数 callback, 一个回调函数的this值,其中回调函数接受三个参数 currentValue, index, arrary,而题目中, map只传入了回调函数parseInt,其次,parseInt 只接受两个两个参数 string, radix(基数)。
在没有指定基数,或者基数为 0 的情况下,JavaScript 作如下处理:
- 如果字符串 string 以"0x"或者"0X"开头, 则基数是16 (16进制).
- 如果字符串 string 以"0"开头, 基数是8(八进制)或者10(十进制),那么具体是哪个基数由实现环境决- 定。ECMAScript 5 规定使用10,但是并不是所有的浏览器都遵循这个规定。因此,永远都要明确给出radix参数的值。
- 如果字符串 string 以其它任何值开头,则基数是10 (十进制)。
所以本题即问
parseInt('1', 0);
parseInt('2', 1);
parseInt('3', 2);
首先后两者参数不合法.
所以答案是 [1, NaN, NaN]
[typeof null, null instanceof Object]
A. ["object", false]
B. [null, false]
C. ["object", true]
D. other
解析:A
typeof 返回一个表示类型的字符串,instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。
type | result |
---|---|
Undefined | “undefined” |
Null | “object” |
Boolean | “boolean” |
Number | “number” |
String | “string” |
Symbol | “symbol” |
Host object | Implementation-dependent |
Function | “function” |
Object | “object” |
所以typeof null返回object,但是null并不存在于参数 object 的原型链上,所以返回false。
[ [3,2,1].reduce(Math.pow), [].reduce(Math.pow) ]
A. an error
B. [9, 0]
C. [9, NaN]
D. [9, undefined]
解析:A
array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
reduce接收两个参数,一个回调函数,一个可选的将用作累积的初始值。
如果提供了 initialValue,则 reduce 方法会对数组中的每个元素调用一次 callbackfn 函数(按升序索引顺序)。如果未提供 initialValue,则 reduce 方法会对从第二个元素开始的每个元素调用 callbackfn 函数。
回调函数接收四个参数,依次是:
- 通过上一次调用回调函数获得的值。如果向 reduce 方法提供 initialValue,则在首次调用函数时,total 为 initialValue。
- 当前数组元素的值。
- 当前数组元素的数字索引。
- 包含该元素的数组对象。
pow() 方法返回 x 的 y 次幂。
[3, 2, 1].reduce(Math.pow) 拆分开来就是:
Math.pow(3, 2) // 9
Math.pow(9, 1) // 9
但是reduce在两个情况下会抛出异常,当满足下列任一条件时,将引发 TypeError 异常:
- callbackfn 参数不是函数对象。
- 数组不包含元素,且未提供 initialValue。
所以 [].reduce(Math.pow) 会抛出异常
var val = 'smtg';
console.log('Value is ' + (val === 'smtg') ? 'Something' : 'Nothing');
A. Value is Something
B. Value is Nothing
C. NaN
D. other
解析:D
+的优先级大于?,所以原题等价于:
console.log('Value is true' ? 'Something' : 'Nothing') // Something
var name = 'World!';
(function () {
if (typeof name === 'undefined') {
var name = 'Jack';
console.log('Goodbye ' + name);
} else {
console.log('Hello ' + name);
}
})();
A. Goodbye Jack
B. Hello Jack
C. Hello undefined
D. Hello World
解析:A
在javascript里,声明变量或函数会被提升,就是说,变量提升是JavaScript将声明移至作用域 scope (全局域或者当前函数作用域) 顶部的行为。
但是javascript只提升声明,而不是初始化,如果使用一个在已经使用后才声明和初始化的值,这个值将是undefined,所以这题就相当于:
var name = 'World!';
(function () {
var name;
if (typeof name === 'undefined') {
name = 'Jack';
console.log('Goodbye ' + name);
} else {
console.log('Hello ' + name);
}
})();
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
2的53次方是js能正确计算且不失精度的最大整数。 js中可以表示的最大整数不是2的53次方,而是1.7976931348623157e+308。
Math.pow(2, 53) = 9007199254740992。最大值加1还是9007199254740992,所以这个循环会一直下去
9007199254740992 +1还是 9007199254740992 ,这就是因为精度问题,如果 9007199254740992 +11或者 9007199254740992 +111的话,值是会发生改变的,只是这时候计算的结果不是正确的值,就是因为精度丢失的问题。
var ary = [0,1,2];
ary[10] = 10;
ary.filter(function(x) { return x === undefined;});
A. [undefined × 7]
B. [0, 1, 2, 10]
C. []
D. [undefined]
解析:C
array.filter(function(currentValue,index,arr), thisValue)
filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。filter接收两个参数, 一个回调函数,一个是可选的回调函数的this值,默认为undefined。
回调函数依次接收三个参数:
- 必须。当前元素的值
- 可选。当期元素的索引值
- 可选。当期元素属于的数组对象
再说稀疏矩阵,当你取数组中某个没有定义的数时:
arr[4] // undefined
但是当你遍历它时,你会发现它并没有元素。JavaScript会跳过这些缝隙,所以答案为: []
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'));
A. Case A
B. Case B
C. Do not know!
D. undefined
解析:C
switch 是严格比较,用的是 ===,String 实例和字符串不一样。
var s_prim = 'foo';
var s_obj = new String(s_prim);
console.log(typeof s_prim); // "string"
console.log(typeof s_obj); // "object"
console.log(s_prim === s_obj); // false
所以答案是 Do not know!
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'));
A. Case A
B. Case B
C. Do not know!
D. undefined
解析:A
String(x)不创建对象,但返回一个字符串,即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);
A. [true, true, true, true, true]
B. [true, true, true, true, false]
C. [true, true, true, false, false]
D. [true, true, false, false, false]
解析:C
7 % 2 => 1
4 % 2 => 0
'13' % 2 => 1
-9 % % 2 => -1
Infinity % 2 => NaN
Array.isArray( Array.prototype )
A. true
B. false
C. error
D. other
解析:A
Array.prototype 本身也是一个 Array
var a = [0];
if ([0]) {
console.log(a == true);
} else {
console.log("wut");
}
A. true
B. false
C. "wut"
D. other
解析:B
- boolean([0]) === true
- [0] == true
- true 转换为数字 => 1
- [0] 转化为数字失败, 转化为字符串 ‘0’, 转化成数字 => 0
- 0 !== 1
[]==[]
A. true
B. false
C. error
D. other
解析:B
[] 是Object, 两个 Object 不相等
'5' + 3
'5' - 3
A. "53", 2
B. 8, 2
C. error
D. other
解析:A
-会尽可能的将两个操作数变成数字,而 + 如果两边不都是数字,那么就是字符串拼接
[1 < 2 < 3, 3 < 2 < 1]
A. [true, true]
B. [true, false]
C. error
D. other
解析:A
'<‘运算符顺序是从左到右,所以变成了[true < 3, false < 1],接着进行隐式类型转换,’<'操作符的转换规则:
- 如果两个操作值都是数值,则进行数值比较
- 如果两个操作值都是字符串,则比较字符串对应的字符编码值
- 如果只有一个操作值是数值,则将另一个操作值转换为数值,进行数值比较
- 如果一个操作数是对象,则调用valueOf()方法(如果对象没有valueOf()方法则调用toString()方法),得到的结果按照前面的规则执行比较
- 如果一个操作值是布尔值,则将其转换为数值,再进行比较
这里首先通过Number()转换为数字然后进行比较,true转换成1,false转换成0,就变成了[1 < 3, 0 < 1]
3.toString()
3..toString()
3...toString()
A. "3", error, error
B. "3", "3.0", error
C. error, "3", error
D. other
解析:C
很多人都踩过3.toString()的坑,虽然JavaScript会在调用方法时对原始值进行包装,但是这个点是小数点呢、还是方法调用的点呢,于是乎第一个就是error了,因为JavaScript解释器会将其认为是小数点。
而第二个则很好说通了,第一个点解释为小数点,变成了(3.0).toString(),结果就是"3"了。
第三个也是,第一个点为小数点,第二个是方法调用的点,但是后面接的不是一个合法的方法名,于是乎就error了。
(function(){
var x = y = 1;
})();
console.log(y);
console.log(x);
A. 1, 1
B. error, error
C. 1, error
D. other
解析:C
在作用域内,变量定义和函数定义会先行提升,所以里面就变成了:
(function(){
var x;
y = 1;
x = 1;
})();
这点会问了,为什么不是var x, y,这就是坑的地方…这里只会定义第一个变量x,而y则会通过不使用var的方式直接使用,于是乎就隐式定义了一个全局变量y,所以,y是全局作用域下,而x则是在函数内部,结果就为1, error
var a = /123/,
b = /123/;
a == b
a === b
A. true, true
B. true, false
C. false, false
D. other
解析:C
JavaScript中的正则表达式依旧是对象,使用typeof运算符就能得出结果:
console.log(typeof /123/);
//输出结果:
//"object"
==运算符左右两边都是对象时,会比较他们是否指向同一个对象,可以理解为C语言中两个指针的值是否一样(指向同一片内存),所以两个结果自然都是false
var a = [1, 2, 3],
b = [1, 2, 3],
c = [1, 2, 4]
a == b
a === b
a > c
a < c
A. false, false, false, true
B. false, false, false, false
C. true, true, false, true
D. other
解析:A
JavaScript中Array的本质也是对象,所以前两个的结果都是false,而JavaScript中Array的>运算符和<运算符的比较方式类似于字符串比较字典序,会从第一个元素开始进行比较,如果一样比较第二个,还一样就比较第三个,如此类推,所以第三个结果为false,第四个为true。
function foo() { }
var oldName = foo.name;
foo.name = "bar";
[oldName, foo.name]
A. error
B. ["", ""]
C. ["foo", "foo"]
D. ["foo", "bar"]
解析:C
使用函数定义方式时,会给function对象本身添加一个name属性,保存了函数的名称,很好理解oldName为foo。name属性时只读的,不允许修改,所以foo.name = “bar”;之后,foo.name还是foo。
var a = {class: "Animal", name: 'Fido'};
a.class
A. "Animal"
B. Object
C. an error
D. other
解析:D
class是关键字。根据浏览器的不同,结果不同:
- chrome的结果: “Animal”
- Firefox的结果:“Animal”
- Opera的结果:“Animal”
- IE 8以上也是: “Animal”
- IE 8 及以下: 报错
var min = Math.min(), max = Math.max()
min < max
A. true
B. false
C. error
D. other
解析:B
Math.min 不传参数返回 Infinity, Math.max 不传参数返回 -Infinity.