44 道 JavaScript 難題(JavaScript Puzzlers!)

這是一套很經典的JavaScript題了,作以前一些題我也以爲稀奇古怪,但一道一道作,記下錯題,去查解釋,作完感受真的很值得,有點像回到高中時候,就想到了沙耶加。若是在學習路上疲憊了,安利大家《墊底辣妹》 。這裏是這套題的原文連接,能夠不看答案一道一道去作。javascript

下一篇《一站到底 ---前端基礎之網絡》 html

1. ["1", "2", "3"].map(parseInt)

答案:[1, NaN, NaN]
解析:parseInt (val, radix) :兩個參數,val值,radix基數(就是多少進制轉換)
     map 能傳進回調函數 3參數 (element, index, array)
     parseInt('1', 0);  //0表明10進制
     parseInt('2', 1);  //沒有1進制,不合法
     parseInt('3', 2);  //2進制根本不會有3
鞏固:["1", "1", "11","5"].map(parseInt) //[1, NaN, 3, NaN]
      parseInt('13',2)    // 1 ,
      計算機在二進制只認識0,1,parseInt轉換時就看成不認識的字符忽略了
      parseInt('18str')     //18   10進制能認識到9
      parseInt(1/0,19)    // 18  
      1/0 == Infinity 19 進制計算機能認識最後一個字符是i 
      詳細解析在下面的連接
複製代碼

鞏固題詳細解釋在stackoverflow前端

2. [typeof null, null instanceof Object]

答案:["object", false]
解析:null表明空對象指針,因此typeof判斷成一個對象。能夠說JS設計上的一個BUG
     instanceof 實際上判斷的是對象上構造函數,null是空固然不可能有構造函數
鞏固:null == undefined //true    null === undefined //flase
複製代碼

3. [ [3,2,1].reduce(Math.pow), [].reduce(Math.pow) ]

答案:an error
解析:Math.pow (x , y)  x 的 y 次冪的值
     reduce(fn,total)
     fn (total, currentValue, currentIndex, arr) 
         若是一個函數不傳初始值,數組第一個組默認爲初始值.
         [3,2,1].reduce(Math.pow)
         Math.pow(3,2) //9
         Math.pow(9,1) //9
鞏固:[].reduce(Math.pow)       //空數組會報TypeError
     [1].reduce(Math.pow)      //只有初始值就不會執行回調函數,直接返回1
     [].reduce(Math.pow,1)     //只有初始值就不會執行回調函數,直接返回1
     [2].reduce(Math.pow,3)    //傳入初始值,執行回調函數,返回9
複製代碼

4.

var val = 'smtg';
 console.log('Value is ' + (val === 'smtg') ? 'Something' : 'Nothing');
複製代碼

這段代碼的執行結果?java

答案:Something
解析:字符串鏈接比三元運算有更高的優先級 
     因此原題等價於 'Value is true' ? 'Somthing' : 'Nonthing' 
     而不是 'Value   is' + (true ? 'Something' : 'Nonthing')
鞏固:
    1 || fn() && fn()   //1  
    1 || 1 ? 2 : 3 ;    //2  
   鞏固的解釋請看下面這篇文章
複製代碼

Like Sunday, Like Rain - JavaScript運算符優先級之謎es6

5.

var name = 'World!';
(function () {
if (typeof name === 'undefined') {
    var name = 'Jack';
    console.log('Goodbye ' + name);
} else {
    console.log('Hello ' + name);
}
})();
複製代碼

這段代碼的執行結果?chrome

答案:Goodbye Jack
解析:(1)typeof時 name變量提高。 在函數內部之聲明未定義
     (2)typeof優先級高於===
鞏固:
    var str = 'World!';   
    (function (name) {
    if (typeof name === 'undefined') {
        var name = 'Jack';
        console.log('Goodbye ' + name);
    } else {
        console.log('Hello ' + name);
    }
    })(str);
    答案:Hello World 由於name已經變成函數內局部變量
複製代碼

6.

var END = Math.pow(2, 53);
var START = END - 100;
var count = 0;
for (var i = START; i <= END; i++) {
    count++;
}
console.log(count);
複製代碼

這段代碼的執行結果?編程

答案:other ,不是101
解析:js中能夠表示的最大整數不是2的53次方,而是1.7976931348623157e+308。2的53次方不是js能表示的最大整數而應該是能正確計算且不失精度的最大整數,
鞏固:
     var END = 1234567635;
     var START = END - 1024;
     var c = count = 0;
     for (var i = START; i <= END; i++) {
        c = count++;
     }
     console.log(count);   //1025
     console.log(c);       //1024
複製代碼

7.

var ary = [0,1,2];
ary[10] = 10;
ary.filter(function(x) { return x === undefined;}); 
複製代碼

這段代碼的執行結果?數組

答案:[]
解析:filter() 不會對空數組進行檢測。會跳過那些空元素
鞏固:
      var ary = [0,1,2,undefined,undefined,undefined,null];
      ary.filter(function(x) { return x === undefined;});
      // [undefined, undefined, undefined] 
複製代碼

8.

var two   = 0.2
var one   = 0.1
var eight = 0.8
var six   = 0.6
[two - one == one, eight - six == two]
複製代碼

這段代碼的執行結果?瀏覽器

答案:[true, false]
解析:IEEE 754標準中的浮點數並不能精確地表達小數
鞏固:var two   = 0.2;
     var one   = 0.1;
     var eight = 0.8;
     var six   = 0.6;
     ( eight - six ).toFixed(4) == two 
     //true
複製代碼

9.

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判斷的是全等(===) ,new String(x)是個對象
鞏固:var a =  new String('A') ;
      a.__proto__
     // String.prototype 實例的原型指向構造函數的原型對象
複製代碼

10.

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('A')就是返回一個字符串
鞏固: var a2 =  'A';
      a2.__proto__                  // String.prototype 
      a1.__proto__ === a2.__proto__  // true 上一題的a.__proto__
      那字符串不是對象爲啥也指向String.prototype?
解析:b是基本類型的值,邏輯上不該該有原型和方法。爲了便於操做,有一種特殊的引用類型(基本包裝類型)String。其實讀取時,後臺會自動完成下面的操做:
      var str = new String("A"); //建立實例
      str.__proto__;             //調用指定屬性和方法
      str = null;                //銷燬實例
      因此 a1.__proto__ === a2.__proto__
      但注意基本包裝類型特殊就在於它對象(str)的生命週期,只存在於一行代碼(a1.__proto__ === a2.__proto__)的執行瞬間。
      這也就解釋了爲啥字符串也能操做屬性和方法但不能添加。基本包裝類型有三個(String,Number,Boolean)
     (詳情請看《js高程》 5.6基本包類型 P119)
複製代碼

11.

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]
解析:%若是不是數值會調用Number()去轉化
     '13' % 2       // 1
      Infinity % 2  //NaN  Infinity 是無窮大
      -9 % 2        // -1
鞏固: 9 % -2        // 1   餘數的正負號隨第一個操做數
複製代碼

12.

parseInt(3, 8)
parseInt(3, 2)
parseInt(3, 0)
複製代碼

這段代碼的執行結果?

答案:3  NaN  3
解析:2進制不可能有3
複製代碼

13.

Array.isArray( Array.prototype )
複製代碼

這段代碼的執行結果?

答案:true
解析:Array.prototype是一個數組
     數組的原型是數組,對象的原型是對象,函數的原型是函數
複製代碼

14.

var a = [0];
if ([0]) {
  console.log(a == true);
} else {
  console.log("wut");
}
複製代碼

這段代碼的執行結果?

答案:false
解析:[0]的boolean值是true
      console.log(a == true); // 轉換爲數字進行比較, a轉換先toString,轉化成'0',再Number('0') 轉化成數值0
      Number(true) => 1 ,全部是false
複製代碼

15.[]==[]

答案:false
解析:兩個引用類型, ==比較的是引用地址
鞏固:[]== ![] 
     (1)! 的優先級高於== ,右邊Boolean([])是true,取返等於 false
     (2)一個引用類型和一個值去比較 把引用類型轉化成值類型,左邊0
     (3)因此 0 == false  答案是true
複製代碼

16.

'5' + 3
'5' - 3
複製代碼

這段代碼的執行結果?

答案:53  2
解析:加號有拼接功能,減號就是邏輯運算
鞏固:typeof (+"1")   // "number" 對非數值+—常被用來作類型轉換至關於Number()
複製代碼

17. 1 + - + + + - + 1

答案:2
解析:+-又是一元加和減操做符號,就是數學裏的正負號。負負得正哈。 
鞏固: 一元運算符還有一個經常使用的用法就是將自執行函數的function從函數聲明變成表達式。
      經常使用的有 + - ~ ! void
      + function () { }
      - function () { }
      ~ function () { }
      void function () { }
複製代碼

18.

var ary = Array(3);
ary[0]=2
ary.map(function(elem) { return '1'; });
複製代碼

這段代碼的執行結果?

答案:["1", empty × 2]
解析:如過沒有值,map會跳過不會執行回調函數
複製代碼

19.

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會和函數參數綁定。
鞏固:但若是es6付給初始值則沒法修改,由於es6編譯後用了嚴格模式
      function sidEffecting(ary) {
        ary[0] = ary[2];
      }
      function bar(a=1,b,c) {
        c = 10
        sidEffecting(arguments);
        return a + b + c;
    }
       bar(1,1,1)
       //12
    這裏總結一下:嚴格模式和非嚴格模式
    (1)嚴格模式arguments對象是傳入函數內實參列表的靜態副本;非嚴格模式下,指向同一個值的引用 
    (2)嚴格模式變量必須先聲明,才能使用
    (3)嚴格模式中 call apply傳入null undefined保持原樣不被轉換爲window
複製代碼

20.

var a = 111111111111111110000,
b = 1111;
a + b;
複製代碼

這段代碼的執行結果?

答案:11111111111111111000
解析:在JavaScript中number類型在JavaScript中以64位(8byte)來存儲。這64位中有符號位1位、指數位11位、實數位52位。2的53次方時,是最大值。其值爲:9007199254740992(0x20000000000000)。超過這個值的話,運算的結果就會不對.
複製代碼

21.

var x = [].reverse;
x();
複製代碼

這段代碼的執行結果?

答案:error
解析:原來答案是window
      x = [].reverse  是把reverse函數賦值給x
      reverse 函數處理的是調用它的this
      好比 [1,2,3].reverse()時,它的this是[1,2,3]
      之前reverse是非嚴格模式的函數下,沒傳this會默認爲window
      如今的reverse使用嚴格模式編寫,應該是undefined,因此會報類型轉換錯誤
      更多解釋能夠看下面"fe-baidu"的評論
複製代碼

22.Number.MIN_VALUE > 0

答案:true
解析:MIN_VALUE 屬性是 JavaScript 中可表示的最小的數(接近 0 ,但不是負數)。它的近似值爲 5 x 10-324。
複製代碼

23.[1 < 2 < 3, 3 < 2 < 1]

答案:[true,true]
解析: 1 < 2    =>  true;
      true < 3 =>  1 < 3 => true;
      
      3 < 2     => false;
      false < 1 => 0 < 1 => true;
複製代碼

24. 2 == [[[2]]]

答案:true
解析:值和引用類型去比較,把引用類型轉話成值類型
     [[[2]]])//2
鞏固:++[[]][+[]]+[+[]] //"10"
     (1)(++([[]][+[]])) + [+[]]  //運算符權重判斷,安利一下第四題下面的文章
     (2)(++([[]][0])) + [0]      // 16題中咱們講過+用來作類型轉換Number([]) ===0
     (3)+([] + 1) + [0]            //[[]]數組的第0項就是[],++表明自增+1
       *******  注意這一步不是 (++[]) + [0] 這樣是錯誤的   **********
     (4)+([] + 1) + [0]           // 前面+將"1"轉成數字1 後邊,+是拼接 "0" 因此是字符串"10"
      這題的詳細解釋在下面的連接中。高票答案解釋的很是贊,推薦閱讀
複製代碼
鞏固題詳細解釋在stackoverflow

25.

3.toString()
3..toString()
3...toString()
複製代碼

這段代碼的執行結果?

答案:error, "3", error
解析:由於在 js 中 1.1, 1., .1 都是合法的數字. 那麼在解析 3.toString 的時候這個 . 究竟是屬於這個數字仍是函數調用呢? 只能是數字, 由於3.合法啊!
複製代碼

26.

(function(){
  var x = y = 1;
})();
console.log(y);
console.log(x);
複製代碼

這段代碼的執行結果?

答案:1, error
解析:y 被賦值成全局變量,等價於
     y = 1 ;
     var x = y;
複製代碼

27.

var a = /123/,
b = /123/;
a == b
a === b
複製代碼

這段代碼的執行結果?

答案:false, false
解析:正則是對象,引用類型,相等(==)和全等(===)都是比較引用地址
複製代碼

28.

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
解析:相等(==)和全等(===)仍是比較引用地址
     引用類型間比較大小是按照字典序比較,就是先比第一項誰大,相同再去比第二項。
複製代碼

29.

var a = {}, b = Object.prototype;
[a.prototype === b, Object.getPrototypeOf(a) === b]    
複製代碼

這段代碼的執行結果?

答案:false, true
解析:Object 的實例是 a,a上並無prototype屬性
     a的__poroto__ 指向的是Object.prototype,也就是Object.getPrototypeOf(a)。a的原型對象是b
複製代碼

30.

function f() {}
var a = f.prototype, b = Object.getPrototypeOf(f);
a === b         
複製代碼

這段代碼的執行結果?

答案:false
解析:a是構造函數f的原型 : {constructor: ƒ}
     b是實例f的原型對象 : ƒ () { [native code] }
複製代碼

31.

function foo() { }
var oldName = foo.name;
foo.name = "bar";
[oldName, foo.name]     
複製代碼

這段代碼的執行結果?

答案:["foo", "foo"]
解析:函數的名字不可變.
複製代碼

32."1 2 3".replace(/\d/g, parseInt)

答案:"1 NaN 3"
解析:replace() 回調函數的四個參數:
      一、匹配項  
      二、與模式中的子表達式匹配的字符串  
      三、出現的位置  
      四、stringObject 自己 。
若是沒有與子表達式匹配的項,第二參數爲出現的位置.因此第一個參數是匹配項,第二個參數是位置
 parseInt('1', 0)
 parseInt('2', 2)  //2進制中不可能有2
 parseInt('3', 4)
鞏固:
   "And the %1".replace(/%([1-8])/g,function(match,a , b ,d){
      console.log(match +"  "+ a + " "+ b +" "+d )
    });
   //%1  1 8 And the %1 
複製代碼

33.

function f() {}
var parent = Object.getPrototypeOf(f);
f.name // ?
parent.name // ?
typeof eval(f.name) // ?
typeof eval(parent.name) //  ?  
複製代碼

這段代碼的執行結果?

答案:"f", "Empty", "function", error
解析:f的函數名就是f
     parent是f原型對象的名字爲"" ,
     先計算eval(f.name) 爲 f,f的數據類型是function
     eval(parent.name) 爲undefined, "undefined"
複製代碼

34.

var lowerCaseOnly =  /^[a-z]+$/;
lowerCaseOnly.test(null), lowerCaseOnly.test()]
複製代碼

這段代碼的執行結果?

答案:[true, true]
解析:這裏 test 函數會將參數轉爲字符串. 'nul', 'undefined' 天然都是全小寫了
複製代碼

35.[,,,].join(",")

答案:",,"
解析:由於javascript 在定義數組的時候容許最後一個元素後跟一個,
     因此這個數組長度是3,
鞏固: [,,1,].join(".").length //  3 
複製代碼

36.

var a = {class: "Animal", name: 'Fido'};
a.class   
複製代碼

這段代碼的執行結果?

答案:other
解析:這取決於瀏覽器。類是一個保留字,可是它被Chrome、Firefox和Opera接受爲屬性名。在另外一方面,每一個人都會接受大多數其餘保留詞(int,私有,拋出等)做爲變量名,而類是VordBoint。
複製代碼

37.var a = new Date("epoch")

答案:other
解析:您獲得「無效日期」,這是一個實際的日期對象(一個日期的日期爲true)。但無效。這是由於時間內部保持爲一個數字,在這種狀況下,它是NA。
      在chrome上是undefined 
      正確的是格式是var d = new Date(year, month, day, hours, minutes, seconds, milliseconds);
複製代碼

38.

var a = Function.length,
b = new Function().length
a === b
複製代碼

這段代碼的執行結果?

答案:false
解析:首先new在函數帶()時運算優先級和.同樣因此從左向右執行
     new Function() 的函數長度爲0
鞏固:function fn () {
         var a = 1;
      }
      console.log(fn.length) 
      //0 fn和new Function()同樣
複製代碼

39.

var a = Date(0);
var b = new Date(0);
var c = new Date();
[a === b, b === c, a === c]
複製代碼

這段代碼的執行結果?

答案:[false, false, false]
解析:當日期被做爲構造函數調用時,它返回一個相對於劃時代的對象(JAN 01 1970)。當參數丟失時,它返回當前日期。當它做爲函數調用時,它返回當前時間的字符串表示形式。
a是字符串   a === b // 數據類型都不一樣,確定是false
b是對象     b === c // 引用類型,比的是引用地址
c也是對象   a === c // 數據類型都不一樣,確定是false
鞏固:  var a = Date(2018);
       var b = Date(2001);
       [a ===b ]
       //[true] Date() 方法得到當日的日期,做爲函數調用不須要,返回的同一個字符串
       "Tue Jun 12 2018 14:36:24 GMT+0800 (CST)" 固然若是a,b執行時間相差1秒則爲false
複製代碼

40.

var min = Math.min(), max = Math.max()
min < max
複製代碼

這段代碼的執行結果?

答案:false
解析: Math.min 不傳參數返回 Infinity, Math.max 不傳參數返回 -Infinity ,Infinity應該大於-Infinity,因此是false
     
鞏固:Number.MAX_VALUE  > Number.MIN_VALUE  //true
複製代碼

41.

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]
解析: /g有一個屬性叫lastIndex,每次匹配若是沒有匹配到,它將重置爲0,若是匹配到了,他將記錄匹配的位置。咱們看一個簡單的例子吧。
        var numRe  = /num=(\d)/g;
         numRe.test("num=1abcwewe") //true
         numRe.lastIndex            //5     匹配到num=1後在5的索引位置
         numRe.exec("num=1")        //fales 此次要從5的索引位置,開始匹配
         numRe.lastIndex            //0     上一次匹配失敗了numRe.lastIndex重製爲0
複製代碼

42.

var a = new Date("2014-03-19"),
b = new Date(2014, 03, 19);
[a.getDay() === b.getDay(), a.getMonth() === b.getMonth()]
複製代碼

這段代碼的執行結果?

答案:[false, false]
解析: var a = new Date("2014-03-19")    //可以識別這樣的字符串,返回想要的日期
      Wed Mar 19 2014 08:00:00 GMT+0800 (CST)
      b = new Date(2014, 03, 19);       //參數要按照索引來
      Sat Apr 19 2014 00:00:00 GMT+0800 (CST)
      月是從0索引,日期是從1 
      getDay()是獲取星期幾
      getMonth()是獲取月份因此都不一樣
鞏固: [a.getDate() === b.getDate()] //true
複製代碼

43.

if ('http://giftwrapped.com/picture.jpg'.match('.gif')) {
    'a gif file'
  } else {
    'not a gif file'
  }
複製代碼

這段代碼的執行結果?

答案:'a gif file'
解析: String.prototype.match 接受一個正則, 若是不是, 按照 new RegExp(obj) 轉化. 因此 . 並不會轉義 。 那麼 /gif 就匹配了 /.gif/
鞏固: if ('http://giftwrapped.com/picture.jpg'.indexOf('.gif')) {
        'a gif file'
      } else {
        'not a gif file'
      }
      //indexOf若是匹配不到返回是-1   因此是 'a gif file' 
複製代碼

44.

function foo(a) {
  var a;
  return a;
}
function bar(a) {
    var a = 'bye';
    return a;
}
[foo('hello'), bar('hello')]
複製代碼

這段代碼的執行結果?

答案:["hello", "bye"]
解析:最後一題很簡單吧,變量聲明
複製代碼

下一篇: 在你身邊你左右 --函數式編程別煩惱

相關文章
相關標籤/搜索