懷疑人生的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"]
在作用域裏已經存在的變量不會被重複聲明
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章