20個 Js 變態題解析

原題來自: javascript-puzzlersjavascript

第一題java

/*
         * 解析:
         *    map的語法:.map(callback(index,domElement))
         *     map接收兩個參數: map調用者this(aray)和回調函數,回調函數有兩個參數:
                     若是this是普通數組,index是當前遍歷的元素,domElement是索引
                     若是this是jquery對象數組,index是索引,domElement是當前遍歷的元素
             return: 由回調函數中的返回值組成的新的數組
         *  parseInt的語法:parseInt(string, radix), 
         *     string必選。要被解析的字符串 
         *     radix可選。解析數字的基數,介於2~36之間,省略或爲0則將以10爲基數來解析,
                         小於2或大於36 則 parseInt() 將返回 NaN。
         *    return: 解析後的數字
             
         *    因此本題就是問:
         *    parseInt('1', 0);
         *    parseInt('2', 1);
         *    parseInt('3', 2);
         *
         *  因此結果輸出: [1, NaN, NaN]
         */
        console.info(["1", "2", "3"].map(parseInt));

第二題jquery

/*
         * 解析:
         *    typeof 返回一個表示類型的字符串
             typeof 的結果請看下面:
             **type**         **result**
             Undefined   "undefined"
             Null        "object"
             Boolean     "boolean"
             Number      "number"
             String      "string"
             Symbol      "symbol"
             Host object Implementation-dependent
             Function    "function"
             Object      "object"

             instanceof 運算符用來檢測 constructor.prototype 是否存在於參數 object 的原型鏈上
             
             因此輸出["object", false]
         */
        function two(){
            console.info([typeof null, null instanceof Object]); //["object", false]
        }

第三題git

/*
          解析:
             reduce語法:array.reduce(callbackfn[, initialValue])
                array必需。一個數組對象。
                callbackfn 必需。
                    回調函數接受四個參數 previousValue, currentValue, currentIndex, array。
                    對於數組中的每一個元素,reduce 方法都會調用 callbackfn 函數一次。
                initialValue 可選。若是指定 initialValue,則它將用做初始值來啓動累積。
                            第一次調用 callbackfn 函數會將此值做爲參數而非數組值提供。
            
                當知足下列任一條件時,將引起 TypeError 異常:
                    1.callbackfn 參數不是函數對象。
                    2.數組不包含元素,且未提供 initialValue。
            Math.pow語法: Math.pow(x,y)。
                pow() 方法可返回 x 的 y 次冪的值。
            
            因此第二個表達式會報異常. 
            第一個表達式等價於 Math.pow(3, 2) => 9; Math.pow(9, 1) =>9
         */
        console.info([ [3,2,1].reduce(Math.pow), [].reduce(Math.pow) ]);

第四題github

/*
   解析:
     + 優先級大於 ?
   此題等價於: 'Value is true' ? 'Something' : 'Nothing'
   因此結果是:'Something'
*/
var val = 'smtg';
console.log('Value is ' + (val === 'smtg') ? 'Something' : 'Nothing');

第五題數組

/*
    解析:
       變量聲明提早,在 JavaScript中, functions 和 variables 會被提高。
       變量提高是JavaScript將聲明移至做用域 scope (全局域或者當前函數做用域) 頂部的行爲。
    此題至關於:
    var name = 'World!';
    (function () {
        var name;
        if (typeof name === 'undefined') {
            name = 'Jack';
            console.log('Goodbye ' + name);
        } else {
            console.log('Hello ' + name);
        }
    })();
    因此結果是:Goodbye Jack
*/
var name = 'World!';
(function () {
    if (typeof name === 'undefined') {
        var name = 'Jack';
        console.log('Goodbye ' + name);
    } else {
        console.log('Hello ' + name);
    }
})();

第六題app

/*
    [JavaScript中的稀疏數組與密集數組][1]
    
    解析:
      通常來講,JavaScript中的數組是稀疏的,也就是說,數組中的元素之間能夠有空隙
      其實在javascript中並無常規的數組,全部的數組其實就是一個對象。
      javascript的數組根本沒有索引,由於索引是數字,而js中數組的索引是string,
      arr[1]其實就是arr["1"],給arr["1000"] = 1,arr.length也會自動變爲1001.
      這些表現的根本緣由就是,JavaScript中的對象就是字符串到任意值的鍵值對.注意鍵只能是字符串.
    
    看一下 Array.prototype.filter 的部分代碼:
    
    var t = Object(this);
    var len = t.length >>> 0;
    if (typeof fun !== 'function') {
      throw new TypeError();
    }
    var res = [];
    var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
    for (var i = 0; i < len; i++) {
      if (i in t) { // 注意這裏!!!
        var val = t[i];
        if (fun.call(thisArg, val, i, t)) {
          res.push(val);
        }
      }
    }
    從上面可知filter對數組進行遍歷時,會首先檢查這個索引值是否是數組的一個屬性.測試一下:
    console.info(0 in ary); //true
    console.info(1 in ary); //true
    console.info(4 in ary); //false
    console.info(10 in ary); // false
    也就是說3~9的索引根本沒有是初始化
    
    因此答案:[];
*/
var ary = [0,1,2];
ary[10] = 10;
console.info(ary.filter(function(x) { return x === undefined;}));

第七題dom

/*    
    答案:[true, false]
    解析:
        JavaScript的設計缺陷?浮點運算:0.1 + 0.2 != 0.3
        其實在大多數語言裏在作浮點運算時都會有丟失精度的問題。
        console.info(0.7+0.1);//輸出0.7999999999999999
        console.info(0.2+0.1);//輸出 0.30000000000000004
        console.info(0.5+0.1); //輸出0.6
        那這是js的問題嗎?固然不是。你的電腦作着正確的二進制浮點運算,
        但問題是你輸入的是十進制的數,電腦以二進制運算,
        這二者並非老是轉化那麼好的,有時候會獲得正確的結果,但有時候就不那麼幸運了
*/
var two   = 0.2
var one   = 0.1
var eight = 0.8
var six   = 0.6
[two - one == one, eight - six == two]

第八題函數

/*
    解析:
        switch 是嚴格比較。
        直接看這個:
        var str = 'foo';
        var obj = new String(str);

        console.log(typeof str); // "string"
        console.log(typeof obj);  // "object"
        console.log(str === obj); // false
    
    答案: 'Do not know!'
*/
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'));

第九題測試

/*
    解析:
    仍是上題的知識點,不過String 不只是一個構造函數,直接調用會返回一個字符串

    答案:'Case A'
*/
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'));

第十題

/*
    解析: 這題沒什麼可說的,
    console.info([] instanceof Array); // true
    console.info([] instanceof Object); // true
    []是一個數組對象. [] == [] 等價於:
    var a = [];
    var b = [];
    a == b; 因此確定是false
*/
console.log([]==[]); //false

第十一題

/*
    解析:
        +用來表示兩個數的和或者字符串拼接, -表示兩數之差
        - 會盡量的將兩個操做數變成數字, 而 + 若是兩邊不都是數字, 那麼就是字符串拼接
*/
console.info('5' + 3) // 53
console.info('5' - 3) // 2

第十二題

/*
    解析:
        函數內部的arguments局部變量其實就是該函數的實際參數數組,
        因此c就是arguments[2], 也就是說對c的修改就是對arguments[2]的修改。
        因此答案是:21, 若是說這個題還能夠, 下面第十三題真就有些變天了
*/
function sidEffecting(ary) {
  ary[0] = ary[2];
}
function bar(a,b,c) {
  c = 10
  sidEffecting(arguments);
  return a + b + c;
}
bar(1,1,1);

第十二題

/*
    解析:
        當函數參數涉及到 any rest parameters,
        any default parameters or any destructured parameters 的時候, 
        這個 arguments 就不在是一個 mapped arguments object 了....., 
        因此答案是12,這個須要好好體會一下
*/
function sidEffecting(ary) {
  ary[0] = ary[2];
}
function bar(a,b,c=3) {
  c = 10
  sidEffecting(arguments);
  return a + b + c;
}
bar(1,1,1);

第十三題

/*
    同第六題 稀疏數組,題中數組長度爲3,可是隻初始化了一個索引,array上的操做會跳過未初始化的索引
    答案:["1", undefined, undefined]
*/
var ary = Array(3);
ary[0]=2
ary.map(function(elem) { return '1'; });

第十四題

/*
   解析:
    這個題會讓人誤覺得是 2 > 1 && 2 < 3 其實不是的.
    這個題至關於:
    1 < 2 => true;
    true < 3 => 1 < 3 =>true;
    3 < 2 => false;
    false < 1 => 0 < 1 =>true;
    
    因此答案是:[true, true]
*/
console.info([1 < 2 < 3, 3 < 2 < 1]);

第十五題

/*
    解析:
      一、對於string,number等基礎類型,==和===是有區別的
       1)不一樣類型間比較,==只比較「轉化成同一類型後的值」看「值」是否相等,
            ===若是類型不一樣,其結果就是不等
       2)同類型比較,直接進行「值」比較,二者結果同樣
      二、對於Array,Object等高級類型,==和===是沒有區別的
            進行「指針地址」比較
      三、基礎類型與高級類型,==和===是有區別的
       1)對於==,將高級轉化爲基礎類型,進行「值」比較
       2)由於類型不一樣,===結果爲false

        
*/
console.info(2 == [2]); // true

第十六題

/*
    由於在 js 中 1.1, 1., .1 都是合法的數字. 
    那麼在解析 3.toString 的時候這個 . 究竟是屬於這個數字仍是函數調用呢? 只能是數字, 由於3.合法啊!
  */

3.toString() //error
3..toString() // '3'
3...toString() // error
var a = 3;
a.toString(); // '3'

第十七題

/*
    解析:
        y 被賦值到全局. x 是局部變量. 因此打印 x 的時候會報 ReferenceError
    
*/
(function(){
  var x = y = 1;
})();
console.log(y); // 1
console.log(x); // error

第十八題

/*
    解析:
    具體的對象沒有prototype屬性,因此a.prototype是undefined,
    Object.getPrototypeOf(obj) 返回一個具體對象的原型
    
    答案:false, true
*/
var a = {}, b = Object.prototype;
[a.prototype === b, Object.getPrototypeOf(a) === b]

第十九題

/*
    解析:
       用new建立f的實例的原型指向 f.prototype,也就是:
       f.prototype == Object.getPrototypeOf(new f()); // true
       而Object.getPrototypeOf(f)是 f 函數的原型,也就是:
       Object.getPrototypeOf(f) == Function.prototype; //true
      因此答案是 false
*/
function f() {}
var a = f.prototype, b = Object.getPrototypeOf(f);
a === b

第二十題

/*
    解析:
        foo.name 是函數的名字,函數的名字是不可變的,
        這裏出錯的緣由是容易把name理解成foo的 static 屬性,
        個人理解是name是foo函數的固有屬性,能夠理解爲是final的
    答案:['foo', 'foo']
*/
function foo() { }
var oldName = foo.name;
foo.name = "bar";
[oldName, foo.name]

ps:筆者只是按着本身的理解整理的,水平有限,有不對之處還望指出。
參考:https://github.com/xiaoyu2er/blog/issues

相關文章
相關標籤/搜索