怀疑人生的44问-- JavaScript Puzzlers题目详解

题目在这里:http://javascript-puzzlers.herokuapp.com/


1. 
Q: ["1", "2", "3"].map(parseInt)
A: [1, NaN, NaN]
parseInt接收2个参数(val,radix)
map的回调函数接收3个参数(elem,idx,arr)
所以相当于把idx作为radix
parseInt("1",0) - radix为0时会被忽略 - 1
parseInt("2",1) - 1进制下不存在2 -NaN


2. 
Q: [typeof null, null instanceof Object]
A: ["object", false]
[typeof undefined, undefined instanceof Object]
["undefined", false]


3.
Q: [ [3,2,1].reduce(Math.pow), [].reduce(Math.pow) ] 
A: an error
原理同第一题
另外,对空数组调用没有初始值的reduce会报错!Reduce of empty array with no initial value
而[].reduce(Math.pow,0) === 0 //true
这个case提醒我们在不能保证数组不为空的情况下reduce一定要给初始值参数


4. 
Q: var val = 'smtg';
   console.log('Value is ' + (val === 'smtg') ? 'Something' : 'Nothing');
A: "Something"
运算符优先级 + 比 条件运算符?更高。更全参考:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Operator_Precedence


5.
Q:  var name = 'World!';
(function () {
    if (typeof name === 'undefined') {
        var name = 'Jack';
        console.log('Goodbye ' + name);
    } else {
        console.log('Hello ' + name);
    }
})();
A:  "Goodbye Jack"
var name 的提升


6. 
Q:  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: 死循环
JS里2^53是最大的值,2^53+1 === 2^53,始终无法满足循环终止条件


7.
Q:  var ary = [0,1,2];
ary[10] = 10;
ary.filter(function(x) { return x === undefined;});
A:  []
[].filter(), map(), reduce() 都会跳过未初始化的undefined


8. 
Q:  var two   = 0.2
var one   = 0.1
var eight = 0.8
var six   = 0.6
[two - one == one, eight - six == two]
A:  [true, false]
JS并不能精确地表达浮点数,经典的0.1+0.2=0.30000000000000004
解决方案日后详细总结


9. & 10.
Q:  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'));
showCase(String('A'));
A:  "Do not know!"
"Case A"
switch是严格比较===,new String(x) !== x, String(x) === x
var s1 = 'trick'
var s2 = new String(s1) 
var s3 = String(s1)
s1 == s2  // true
s1 === s2 // false
s1 === s3 // true
typeof s1 // "string"
typeof s2 // "object"


11. 
Q: 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, false, false]
-9 % 2 // -1, 余数的正负号随第一个操作数
Infinity % 2 // NaN


12. 
Q: parseInt(3, 8)
   parseInt(3, 2)
   parseInt(3, 0)
A: 3, NaN, 3


13. 
Q: Array.isArray( Array.prototype )
A: true
一个鲜为人知的事实


14. 
Q:  var a = [0];
if ([0]) {
  console.log(a == true);
} else {
  console.log("wut");
}
A:  false
if()为false的:0、-0、null、""、false、undefined、NaN


15.
Q: []==[]
A: false
两个不同的对象,比的是内存地址
[] == ![] // true,优先右侧取!为boolean,左侧强制类型转换[]->false


16.
Q: '5' + 3
   '5' - 3
A: "53", 2
和string做+操作会强制转换成string,字符串拼接
string没有-操作,第二个表达式会强转为number


17.
Q: 1 + - + + + - + 1
A: 2
-> 1+(-(+(+(+(-(+1))))))) -> 1+1 -> 2


18. 
Q:  var ary = Array(3);
ary[0]=2
ary.map(function(elem) { return '1'; });
A:  ["1", undefined × 2]
同7


19.
Q:  function sidEffecting(ary) {
  ary[0] = ary[2];
}
function bar(a,b,c) {
  c = 10
  sidEffecting(arguments);
  return a + b + c;
}
bar(1,1,1)
A:  21 (严格模式下为12)
ES5以前非严格模式下arguments对象与命名参数同步更新
而严格模式下、使用ES6默认参数、rest参数、解构赋值,会使得arguments对象与命名参数分离;


20. 
Q:  var a = 111111111111111110000,
    b = 1111;
a + b;
A:  111111111111111110000
111111111111111110000 已经超过了2^53


21. 
Q: var x = [].reverse;
   x();
知识点是[].reverse()会返回this,罢特浏览器和node环境下均报错
调用window.x()或x.call(window)返回window,原因尚不明白,求解。


22. 
Q: Number.MIN_VALUE > 0
A: true
Number.MIN_VALUE表示的是js中最小的正数


23.
Q: [1 < 2 < 3, 3 < 2 < 1]
A: [true, true]
equals (1<2)<3, (3<2)<1 , true强转为1,false强转为0


24. 
Q: // the most classic wtf
   2 == [[[2]]]
A: true
强制类型转换三条规则:
1. 调用 valueOf()。如果结果是原始值(不是一个对象),则将其转换为一个数字。
2. 否则,调用 toString() 方法。如果结果是原始值,则将其转换为一个数字。
3. 否则,抛出一个类型错误。
右侧使用toString()方法转换为"2",然后显然2=="2",至于具体的强转规则有待继续考察。


25.
Q: 3.toString()
   3..toString()
   3...toString()
A: error, "3", error
3.toString(),js在调用方法时会对原始值进行包装,这里'.'不明确,是小数点符号,还是方法调用所以报错
3..toString()相当于(3.).toString()没毛病
另 .3.toString() === "0.3",也是合法的


26.
Q:  (function(){
var x = y = 1;
})();
console.log(y);
console.log(x);
A:  1, error
相当于var x; x = 1; y = 1; 这样就隐式定义了全局变量y


27.
Q:  var a = /123/,
        b = /123/;
a == b
a === b
A:  false, false
js正则表达式也是对象


28. 
Q:  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
Array比较大小,相当于toString()比较字符串的大小


29. 
Q: var a = {}, b = Object.prototype;
   [a.prototype === b, Object.getPrototypeOf(a) === b]
A: [false, true]
object没有显式原型,
而 Object.getPrototypeOf(obj) 返回对象的隐式原型(该对象的内部[[prototype]]值),即其构造函数的显式原型


30. 
Q: function f() {}
   var a = f.prototype, b = Object.getPrototypeOf(f);
   a === b
A: false
prototype和__proto__不一样


31.
Q:  function foo() { }
var oldName = foo.name;
foo.name = "bar";
[oldName, foo.name]
A:  ["foo", "foo"]
函数的name属性,readonly


32.
Q: "1 2 3".replace(/\d/g, parseInt)
A: "1 NaN 3"
String.prototype.replace(reg,func)
func接收的参数:匹配的字符串、...分组(这里没有)、idx、原始母字符串
相当于parseInt('1', 0), parseInt('2', 2), parseInt('3', 4)


33. 
Q:  function f() {}
var parent = Object.getPrototypeOf(f);
f.name // ?
parent.name // ?
typeof eval(f.name) // ?
typeof eval(parent.name) //  ?
A:  "f", "", "function", undefined
f.name值为"f",eval("f")则会输出f函数,所以结果为"function"
parent实际上是f.__proto__,即Function.prototype,是一个没有name的function


34.
Q: var lowerCaseOnly =  /^[a-z]+$/;
   [lowerCaseOnly.test(null), lowerCaseOnly.test()]
A: [true, true]
这里test函数会将参数转为字符串'null'和'undefined'


35.
Q: [,,,].join(", ")
A: ", , "
js中使用字面量创建数组时,如果最末尾有一个',',会被省略,所以实际上这个数组是有三个undefined元素的数组


36.
Q: var a = {class: "Animal", name: 'Fido'};
   a.class
浏览器相关, ie8及以下报错,其他主流浏览器"Animal"
class是关键字, 取属性名称的时候尽量避免. 如果使用的话请加引号 a['class']


37. 
Q: var a = new Date("epoch")
A: Invalid Date
如果调用Date的构造函数传入一个字符串的话需要符合规范, 即满足 Date.parse 的条件.


38.
Q:  var a = Function.length,
    b = new Function().length
a === b
A:  false
Function.length === 1(就这么定义的)
function实例的length为其显式接收的参数个数,这里是0


39.
Q:  var a = Date(0);
var b = new Date(0);
var c = new Date();
[a === b, b === c, a === c, a == c]
A:  [false, false, false, true]
Date作为普通函数无论是否有参数都返回当前时间的string
Date作为构造函数,可以接收好多种参数,参照点为epoch(1970年1月1日),不传则返回当前时间的object


40.
Q: var min = Math.min(), max = Math.max()
   min < max
A: false
Math.min 不传参数返回 Infinity, Math.max 不传参数返回 -Infinity


41.
Q:  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]
A:  [true, false]
全局正则匹配g会从上次匹配的位置继续检索


42.
Q:  var a = new Date("2014-03-19"),
    b = new Date(2014, 03, 19);
[a.getDay() === b.getDay(), a.getMonth() === b.getMonth()]
A:  [false, false]
并不是同一天,b = new Date(2014, 03, 19) 这种参数构造的其实是2014年4月19日
getDay()返回一周中的第几天,从星期天为0开始数
getMonth() 月份,索引从0开始
getDate() 日期,索引从1开始


43.
Q:  if ('http://giftwrapped.com/picture.jpg'.match('.gif')) {
  'a gif file'
} else {
  'not a gif file'
}
A:  'a gif file'
String.prototype.match() 接受一个regExp, 如果不是则按照new RegExp(obj)强转,这里'.gif'的'.'不会被转义,强转为/.gif/,能匹配'/gif'


44. 
Q:  function foo(a) {
    var a;
    return a;
}
function bar(a) {
    var a = 'bye';
    return a;
}
[foo('hello'), bar('hello')]
A:  ["hello", "bye"]
在作用域里已经存在的变量不会被重复声明
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章