那些年我们一起踩过的坑

极限挑战 43道 JS 题目,你对了多少道!

​ 今天笔者整理了自己曾经踩过的坑,当然,有些坑不掉个几次是记不牢的,有点惨emmm,这些题型涉及的知识面非常广,涵盖了 JS 原型,函数细节,强制转换,闭包扥知识点.而且都是一些非常细节的东西,透过这些细节可以折射出很多高级的 JS 知识点,你可以先思考一下结果,然后在看我的解析,为了解释这些细节知识点,笔者翻了很多书和资料,弥补了很多 JS 知识盲点.

​ 勇士,请开始你的冒险之旅,请认真对待每一道题! 考试时间 120 分钟(非上机考试) Let’s Go!!

  1. parentInt 遇上 map

    ["1","5","2",2].map(parseInt);
    // A [1, 5, 2, 2]
    // B ["1", "5", "2", 2]
    // C [1, NaN, 2, 2]
    // D [1, NaN, NaN, 2]
    

Answer is D.

正确的结果是 [1, NaN, NaN, 2],因为 parseInt 函数接收两个参数,语法parseInt(string, radix),在数组的 map 方法中的回调函数接收3个参数 CallBack(currentValue,currentIndex,array) ;MDN文档中明确指明 parseInt的第二个参数radix为一个介于2到36之间的整数,表示上述字符串的基数。比如参数"10"表示使用我们通常使用的十进制数值系统。始终指定此参数可以消除阅读该代码时的困惑并且保证转换结果可预测。当未指定基数时,不同的实现会产生不同的结果,通常将值默认为10

参考资料:

MDN : parseInt

MDN : Array.prototype.map

  1. 神奇的 null

    [typeof null,null instanceof Object]
    //A ["object",false]
    //B [null, false]
    //C ["object",true]
    //D other
    

    Answer is A.

    很多人可能对于typeof null为 “object” 的结果可能觉得很正常,因为 null就是一个特殊的对象,都是既然是一个对象,为什么 null instanceof Object结果为 false 呢? 其实,typeof null结果为 “object” 这一结果是JavaScript 这门语言的一个 Bug,笔者在**《JavaScript高级程序》**一书中了解过,原理是这样的,不同的对象底层都是二进制,在 JavaScript 中二进制前3位都为 0 的话,会被判断其类型为 “object”,null的二进制全是 0,自然前三位也是 0,所以 typeof null 的结果才是 “object”,而instance运算符是用于测试构造函数的prototype属性是否出现在对象的原型链中的任何位置,object instanceof constructor

    参考资料:

    MDN: instanceof

    MDN: null

  2. 怒气冲天的 reduce

    console.log([3,3,2].reduce(Math.pow))
    console.log([].reduce(Math.pow))
    //A 8, undefined
    //B 81, 0
    //C 81, NaN
    //D 81, TypeError
    

    Answer is D

    数组的reduce语法为: arr.reduce(callback[, initialValue]),回调函数callback接收4个参数,分别为

    accumulator 累计器累计回调的返回值; 它是上一次调用回调时返回的累积值

    currentValue 数组中正在处理的元素

    currentIndex 数组中正在处理的当前元素的索引(可选)。 如果提供了initialValue,则起始索引号为0,否则为1

    array 当前数组

    除了接受回调函数外,还可以接受一个初始值 initialValue => 作为第一次调用 callback函数时的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错。

    函数返回值为函数累计处理的结果

    [3,3,2].reduce(Math.pow)没有设置初始值initialVaule,所以从数组的第0项开始计算,

    第一步: Math.pow(3,3,1,[3,3,2]) 结果是 9,累计结果 9

    第二步: Math.pow(9,2,2,[3,3,2]) 结果是 81,累计结果 81

    [].reduce(Math.pow) 抛出错误,原因,数组为空且没有设置初始值!

    MDN: Array.prototype.reduce

  3. 调皮的优先级

    var status = true;
    console.log("我说:" + status ? "你个糟老头" : "你大爷还是你大爷")
    //A "我说:你个糟老头"
    //B "我说:你大爷还是你大爷"
    //C "你个糟老头"
    //D NaN
    

Answer is C

这里考查的是算术运算符优先级,因为 +的优先级高于? :三元运算符,所以 “我说true” ? “你个糟老头” : “你大爷还是你大爷”,非空字符串在 JS 中的布尔值表示真,所以最终结果为 “你个糟老头”

MDN: 算术运算符优先级

  1. 神出鬼没的变量提升

    var myBehavior = "我要好好学习"
    !function (){
        if(typeof myBehavior == "undefined"){
            var myBehavior = "不,我不想";
        }
        console.log(myBehavior);
    }()
    //A "我要好好学习"
    //B "不,我不想"
    //C undefined
    //D other
    

Answer is B

在 JavaScript 中,函数和变量都存在变量提升的机制

匿名函数在调用时没有输出 “我要好好学习” 而是 “不,我不想”,这是因为 JS 内部存在一个过程分析。

当函数运行的一瞬间主要分析3各方面。

  1. 参数;

  2. 局部变量声明;

  3. 函数声明;

此时引入激活对象(Active Object) 简称 AO

在函数运行的一瞬间,先形成一个激活对象叫ACTIVE OBJEECT ,简称AO.

AO的对象是用来储存一个函数的相关参数,局部变量等。

函数内部无论是引用参数,还是引用局部变量,都到AO上找

AO流程可以这样理解,Show Code =>

var myBehavior = "我要好好学习"
!function (){
    var myBehavior;//变量提升
    if(typeof myBehavior == "undefined"){
        myBehavior = "不,我不想";
    }
    console.log(myBehavior);
}()

MDN: 变量提升

  1. 独特的过滤器

    var arr = [1,2,3];
    	arr[7] = undefined;
    var a = arr.filter(function(item){
        return typeof item == "undefined";
    })
    console.log(a)
    //A [undefined*5]
    //B []
    //C [undefined]
    //D undefined
    

    Answer is C

    filter 为数组中的每个元素调用一次 callback 函数,并利用所有使得 callback 返回 true 或等价于 true 的值的元素创建一个新数组。callback 只会在已经赋值的索引上被调用,对于那些已经被删除或者从未被赋值的索引不会被调用。那些没有通过 callback 测试的元素会被跳过,不会被包含在新数组中。

    MDN: Array.prototype.filter

  2. 字符串陷阱

    var str = new String("A");
    switch(str){
        case "A": 
        	console.log("str is A");
        	break;
        case undefined: 
        	console.log("str is undefined");
        	break;
         case null: 
        	console.log("str is null");
        	break;
        default: 
        	console.log("other");
        	break;
    }
    //A "str is A"
    //B "other"
    //C "str is undefined"
    //D "str is null"
    

Answer is B

switch中的比较是===严格等于的, new String(“A”) 返回的是一个对象,而 String(“A”) 返回的是字符串 “A”.

以下内容采摘至 MDN

基本字符串和字符串对象的区别

请注意区分 JavaScript 字符串对象和基本字符串值 . ( 对于 BooleanNumbers 也同样如此.)

字符串字面量 (通过单引号或双引号定义) 和 直接调用 String 方法(没有通过 new 生成字符串对象实例)的字符串都是基本字符串。JavaScript会自动将基本字符串转换为字符串对象,只有将基本字符串转化为字符串对象之后才可以使用字符串对象的方法。当基本字符串需要调用一个字符串对象才有的方法或者查询值的时候(基本字符串是没有这些方法的),JavaScript 会自动将基本字符串转化为字符串对象并且调用相应的方法或者执行查询。

MDN: String

  1. 连续跳坑的字符串

    var str = String("A");
    switch(str){
        case "A": 
        	console.log("str is A");
        	break;
        case undefined: 
        	console.log("str is undefined");
        	break;
         case null: 
        	console.log("str is null");
        	break;
        default: 
        	console.log("other");
        	break;
    }
    //A "str is A"
    //B "other"
    //C "str is undefined"
    //D "str is null"
    

    Answer is A

    结果解析请看上一题!

  2. 意外的非奇即偶

    //判断奇数
    function isOdd(num){
        return num % 2 == 1;
    }
    //判断偶数
    function isEven(num){
        return num % 2 == 0;
    }
    function isSane(num){
        return isOdd(num) || isEven(num);
    }
    var a = [0,3,2,-9,Infinity];
    //A [true,true,true,true,true]
    //B [true,true,true,true,false]
    //C [true,true,true,false,true]
    //D [true,true,true,false,false]
    

    Answer is D

    在判断数字的情况下,判断奇偶数有的时候不是 % 2 看其结果是否为 1 or 0 决定的,例如如果判断奇数的话, -9 % 2 = -1,-9 虽然是奇数,但是它的模却不是 1,还有 Infinite 代表无穷大,Infinity % 2 = NaN

  3. 无耻的 parseInt 老贼

    parseInt(4,4);
    parseInt(6,37);
    parseInt(010);
    parseInt("010");
    //A 1, 6 10, 10
    //B NaN, 6, 8,10
    //C NaN, 6, 8, 8
    //D other
    

    Answer is D

    上述代码其运行结果为: NaN,NaN,8,10

    parseInt的第二个参数 radix表示基数,范围 2 - 36;

    第一题已有更加详细的解析,如需了解,请自行上拉

  4. 鲜为人知的数组原型

    Array.isArray(Array.prototype);
    //A true
    //B null
    //C false
    //D undefined
    

    Answer is A

    其实数组的原型就是数组,这个知识点个人觉得应该是鲜为人知的,MDN文档说明过

    MDN: Array.prototype

  5. 令人恐惧的强制转换

    var a = [0];
    if ([0]) {
      console.log(a == true);
    } else {
      console.log("wut");
    }
    
    // A. true
    // B. false
    // C. "wut"
    // D. other
    

    Answer is B

    规范指出,== 过程中,如果有一个操作值是布尔值,那么会先把他转化为数字,然后进行 [0] == 1的比较,同时规范指出如果其他类型和数字进行比较,会尝试把这个类型转换为数字在进行宽松比较,而对象(数组也是对象)会调用它的toString()方法,将[0] 转成 “0”,“0” == 1的比较中,字符串 “0” 会转成数字 0,所以 0 == 1结果为false.

    以上资料是笔者在《你不知道的javascript》(中卷)了解的

    强制类型转化个人觉得不是一两句话就可以解释的通,还是得饱读经书才可轻易应付.有兴趣的还可以去 GitHub,查看关于这方面的免费书籍,点击即可跳转 You-Dont-Know-JS

你可能感兴趣的:(前端)