带你填一些JS容易出错的坑

开发 前端
今天给大家介绍关于JavaScript Puzzlers的相关知识,题目主要来自看到过的易错题,希望能够帮助到你!

[[393486]]

前言

题目主要来自看到过的易错题,还有经典的44道 JavaScript Puzzlers!,出自原文链接 stackoverflow 这上面有很多Questions不错的,可以好好补一补基础。

. VS = 操作符优先级

  1. let a = {n : 1}; 
  2.       let b = a; 
  3.       a.x = a = {n: 2}; 
  4.  
  5.        
  6.       console.log(a.x) 
  7.       console.log(b.x) 

输出是什么呢?

真的想明白了吗?

  1. undefined 
  2.  
  3. { n : 2} 

你真的了解作用域吗

  1. var a = 0,   
  2.           b = 0; 
  3.       function A(a) { 
  4.           A = function (b) { 
  5.               console.log(a + b++) 
  6.           } 
  7.           console.log(a++) 
  8.       } 
  9.       A(1) 
  10.       A(2) 

留给你们思考,我可是第一遍就做错了(;′⌒`)

答案 1 4

可以好好想一想,你会茅塞顿开的。

类数组的length

  1. var obj = { 
  2.           "2" : 3, 
  3.           "3" : 4, 
  4.           "length" : 2, 
  5.           "splice" : Array.prototype.splice, 
  6.           "push" : Array.prototype.push 
  7.       } 
  8.       obj.push(1) 
  9.       obj.push(2) 
  10.       console.log(obj) 

这段代码的执行结果?

  1. 答案:Object(4) [empty × 2, 1, 2, splice: ƒ, push: ƒ] 

  1. 解释就是第一次使用push,obj对象的push方法设置obj[2] = 1,obj.length++ 
  2.  
  3. 解释就是第一次使用push,obj对象的push方法设置obj[3] = 2,obj.length++ 
  4.  
  5. 使用console.log()方法输出的时候,因为obj上有length属性和splice方法,故将其作为数组输出打印 
  6.  
  7. 打印时因为数组未设置下标为0和1的值,故打印的结果就是empty,主动获取obj[0] = undefined 

非匿名自执行函数,函数名只读

  1. var b = 10; 
  2.       (function b(){ 
  3.           // 'use strict' 
  4.           b = 20 
  5.           console.log(b) 
  6.       })() 

输出的结果是什么?

  1. Function b 
  1. - 如标题一样,非匿名自执行函数,函数名不可以修改,严格模式下会TypeError, 
  2. - 非严格模式下,不报错,修改也没有用。 
  3. - 查找变量b时,立即执行函数会有内部作用域,会先去查找是否有b变量的声明,有的话,直接复制 
  4. - 确实发现具名函数Function b(){} 所以就拿来做b的值 
  5. - IIFE的函数内部无法进行复制(类似于const) 

非匿名自执行函数 II

  1. var b = 10; 
  2.       (function b(){ 
  3.           // 'use strict' 
  4.           var b = 20 
  5.           console.log(window.b)  
  6.           console.log(b) 
  7.       })() 

输出是多少呢?

  1. 10 
  2. 20 
  3. // 访问b变量的时候,发现var b = 20;在当前作用域中找到了b变量,于是把b的值作为20 

非匿名自执行函数 III

  1. var b = 10; 
  2.       (function b(){ 
  3.           console.log(b) 
  4.           b = 5 
  5.           console.log(window.b) 
  6.           var b = 20 
  7.           console.log(b) 
  8.       })() 

输出的结果是多少呢?

这个问题应该不难,就留给你们思考吧

变量提升

  1. var name = 'World!'
  2. (function () { 
  3.     if (typeof name === 'undefined') { 
  4.         var name = 'Jack'
  5.         console.log('Goodbye ' + name); 
  6.     } else { 
  7.         console.log('Hello ' + name); 
  8.     } 
  9. })(); 

在 JavaScript中, Fun 和 var 会被提升

相当于

  1. var name = 'World!'
  2. (function () { 
  3.     var name
  4.     if (typeof name === 'undefined') { 
  5.         name = 'Jack'
  6.         console.log('Goodbye ' + name); 
  7.     } else { 
  8.         console.log('Hello ' + name); 
  9.     } 
  10. })(); 

巩固一下:

  1. var str = 'World!';    
  2.    (function (name) { 
  3.    if (typeof name === 'undefined') { 
  4.        var name = 'Jack'
  5.        console.log('Goodbye ' + name); 
  6.    } else { 
  7.        console.log('Hello ' + name); 
  8.    } 
  9.    })(str); 
  10.    答案:Hello World 因为name已经变成函数内局部变量 

最大整数

  1. var END = Math.pow(2, 53); 
  2. var START = END - 100; 
  3. var count = 0; 
  4. for (var i = START; i <= END; i++) { 
  5.     count++; 
  6. console.log(count); 

一个知识点:Infinity

  1. 在 JS 里, Math.pow(2, 53) == 9007199254740992 是可以表示的最大值. 最大值加一还是最大值. 所以循环不会停. 

稀疏数组与密数组

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

 执行结果如何呢?

做这个题目,你需要了解稀疏数组和密集数组

  • 译 JavaScript中的稀疏数组与密集数组
  • Array/filter

看过源码的同学应该知道,filter源码中,会去判断数组的这个索引值是不是数组的一个属性,有兴趣的同学可以看看我写的这篇关于数组的:[干货👍]从详细操作js数组到浅析v8中array.js

  1. in ary; => true 
  2. in ary; => false 
  3. 10 in ary; => true 
  4. 也就是说 从 3 - 9 都是没有初始化的'坑'!, 这些索引并不存在与数组中. 在 array 的函数调用的时候是会跳过这些'坑'的. 

所以答案就是[]

浮点运算

  1. var two   = 0.2 
  2. var one   = 0.1 
  3. var eight = 0.8 
  4. var six   = 0.6 
  5. [two - one == one, eight - six == two] 

你认为结果是多少呢?面试遇到这个问题,应该怎么回答呢?

  1. [true,false

可以看看这些文章:

  • 探寻 JavaScript 精度问题以及解决方案
  • 从0.1+0.2=0.30000000000000004再看JS中的Number类型

Switch

  1. function showCase(value) { 
  2.     switch(value) { 
  3.     case 'A'
  4.         console.log('Case A'); 
  5.         break; 
  6.     case 'B'
  7.         console.log('Case B'); 
  8.         break; 
  9.     case undefined: 
  10.         console.log('undefined'); 
  11.         break; 
  12.     default
  13.         console.log('Do not know!'); 
  14.     } 
  15. showCase(new String('A')); 

运行结果如何呢?

  1. switch 是严格比较, String 实例和 字符串不一样. 
  2. 答案自然是'Do not know'  
  3. 所以一般情况下,写switch语句,也建议写default 

String("A")

  1. function showCase2(value) { 
  2.     switch(value) { 
  3.     case 'A'
  4.         console.log('Case A'); 
  5.         break; 
  6.     case 'B'
  7.         console.log('Case B'); 
  8.         break; 
  9.     case undefined: 
  10.         console.log('undefined'); 
  11.         break; 
  12.     default
  13.         console.log('Do not know!'); 
  14.     } 
  15. showCase2(String('A')); 

运行结果呢?

  1. 答案:Case A 
  2. 解析:String('A')就是返回一个字符串 

%运算符

  1. function isOdd(num) { 
  2.     return num % 2 == 1; 
  3. function isEven(num) { 
  4.     return num % 2 == 0; 
  5. function isSane(num) { 
  6.     return isEven(num) || isOdd(num); 
  7. var values = [7, 4, '13', -9, Infinity]; 
  8. values.map(isSane); 

运行的结果如何呢?

  1. 答案:[truetruetruefalsefalse
  2. 解析:%如果不是数值会调用Number()去转化 
  3.      '13' % 2       // 1 
  4.       Infinity % 2  //NaN  Infinity 是无穷大 
  5.       -9 % 2        // -1 
  6. 巩固:9 % -2        // 1   余数的正负号随第一个操作数 

数组的原型是什么

  1. Array.isArray( Array.prototype ) 

这段代码的执行结果?

  1. 答案:true 
  2. 解析:Array.prototype是一个数组 
  3. 数组的原型是数组,对象的原型是对象,函数的原型是函数 

宽松相等 ==

  1. []==[] 

答案是什么呢

  1. 答案:false 
  2. 解析:两个引用类型, ==比较的是引用地址 

== 和 !优先级

  1. []== ![]  

结果是什么呢?

  1. (1)! 的优先级高于== ,右边Boolean([])是true,取返等于 false 
  2. (2)一个引用类型和一个值去比较 把引用类型转化成值类型,左边0 
  3. (3)所以 0 == false  答案是true 

数字与字符串相加减

  1. '5' + 3 
  2. '5' - 3 

结果是多少呢?

  1. 答案:53  2 
  2. 解析:加号有拼接功能,减号就是逻辑运算 
  3. 巩固:typeof (+"1")   // "number" 对非数值+—常被用来做类型转换相当于Number() 

一波骚操作 + - + + + - +

  1. 1 + - + + + - + 1 

结果是多少呢

  1. 答案:2 
  2. 解析:+-又是一元加和减操作符号,就是数学里的正负号。负负得正哈。  
  3. 巩固: 一元运算符还有一个常用的用法就是将自执行函数的function从函数声明变成表达式。 
  4.       常用的有 + - ~ !void 
  5.       + function () { } 
  6.       - function () { } 
  7.       ~ function () { } 
  8.       void function () { } 

又是稀疏数组?Array.prototype.map()

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

输出结果是多少呢?

  1. 稀疏数组 
  2.  
  3. 题目中的数组其实是一个长度为3, 但是没有内容的数组, array 上的操作会跳过这些未初始化的'坑'
  4.  
  5. 所以答案是 ["1", empty × 2] 

这里贴上 Array.prototype.map 的 polyfill.

  1. Array.prototype.map = function(callback, thisArg) { 
  2.  
  3.         var T, A, k; 
  4.  
  5.         if (this == null) { 
  6.             throw new TypeError(' this is null or not defined'); 
  7.         } 
  8.  
  9.         var O = Object(this); 
  10.         var len = O.length >>> 0; 
  11.         if (typeof callback !== 'function') { 
  12.             throw new TypeError(callback + ' is not a function'); 
  13.         } 
  14.         if (arguments.length > 1) { 
  15.             T = thisArg; 
  16.         } 
  17.         A = new Array(len); 
  18.         k = 0; 
  19.         while (k < len) { 
  20.             var kValue, mappedValue; 
  21.             if (k in O) { 
  22.                 kValue = O[k]; 
  23.                 mappedValue = callback.call(T, kValue, k, O); 
  24.                 A[k] = mappedValue; 
  25.             } 
  26.             k++; 
  27.         } 
  28.         return A; 
  29.     }; 

JS是如何存储

  1. var a = 111111111111111110000, 
  2. b = 1111; 
  3. a + b; 

这段代码的执行结果?

  1. 答案:11111111111111111000 
  2. 解析:在JavaScript中number类型在JavaScript中以64位(8byte)来存储。 
  3. 这64位中有符号位1位、指数位11位、实数位52位。 
  4. 2的53次方时,是最大值。 
  5. 其值为:9007199254740992(0x20000000000000)。 
  6. 超过这个值的话,运算的结果就会不对. 

数组比较大小

  1. var a = [1, 2, 3], 
  2.     b = [1, 2, 3], 
  3.     c = [1, 2, 4] 
  4. a ==  b 
  5. a === b 
  6. a >   c 
  7. a <   c 

这段代码的执行结果?

  1. 答案:falsefalsefalsetrue 
  2. 解析:相等(==)和全等(===)还是比较引用地址 
  3.      引用类型间比较大小是按照字典序比较,就是先比第一项谁大,相同再去比第二项。 

三元运算符优先级

  1. var val = 'smtg'
  2. console.log('Value is ' + (val === 'smtg') ? 'Something' : 'Nothing'); 

这段代码的执行结果?

  1. 答案:Something 
  2. 解析:字符串连接比三元运算有更高的优先级  
  3.      所以原题等价于 'Value is true' ? 'Somthing' : 'Nonthing'  
  4.      而不是 'Value   is' + (true ? 'Something' : 'Nonthing'
  5. 巩固: 
  6.     1 || fn() && fn()   //1   
  7.     1 || 1 ? 2 : 3 ;    //2   

原型

  1. var a = {}, b = Object.prototype; 
  2. [a.prototype === b, Object.getPrototypeOf(a) === b]  

执行结果是多少呢

  1. 答案:falsetrue 
  2. 解析:Object 的实例是 a,a上并没有prototype属性 
  3.      a的__poroto__ 指向的是Object.prototype,也就是Object.getPrototypeOf(a)。a的原型对象是b 

原型II

  1. function f() {} 
  2. var a = f.prototype, b = Object.getPrototypeOf(f); 
  3. a === b          

这段代码的执行结果?

  1. 答案:false 
  2. 解析:a是构造函数f的原型 : {constructor: ƒ} 
  3. b是实例f的原型对象 : ƒ () { [native code] } 

函数名称

  1. function foo() { } 
  2. var oldName = foo.name
  3. foo.name = "bar"
  4. [oldName, foo.name]      

代码执行结果是什么?

  1. 答案:["foo""foo"
  2. 解析:函数的名字不可变. 

[typeof null, null instanceof Object]

  1. 答案:["object"false
  2. 解析:null代表空对象指针,所以typeof判断成一个对象。可以说JS设计上的一个BUG 
  3.      instanceof 实际上判断的是对象上构造函数,null是空当然不可能有构造函数 
  4. 巩固:null == undefined //true    null === undefined //flase 

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

  1. 答案:Error 
  2. 解析:Math.pow (x , y)  x 的 y 次幂的值 
  3.      reduce(fn,total) 
  4.      fn (total, currentValue, currentIndex, arr)  
  5.          如果一个函数不传初始值,数组第一个组默认为初始值. 
  6.          [3,2,1].reduce(Math.pow) 
  7.          Math.pow(3,2) //9 
  8.          Math.pow(9,1) //9 
  9.  
  10. 巩固题,可以做一做: 
  11.   [].reduce(Math.pow)       //空数组会报TypeError 
  12.      [1].reduce(Math.pow)      //只有初始值就不会执行回调函数,直接返回1 
  13.      [].reduce(Math.pow,1)     //只有初始值就不会执行回调函数,直接返回1 
  14.      [2].reduce(Math.pow,3)    //传入初始值,执行回调函数,返回9 

replace

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

输出是什么呢?

  1. 答案:"1 NaN 3" 
  2. 解析:replace() 回调函数的四个参数: 
  3.       1、匹配项   
  4.       2、与模式中的子表达式匹配的字符串   
  5.       3、出现的位置   
  6.       4、stringObject 本身 。 
  7. 如果没有与子表达式匹配的项,第二参数为出现的位置.所以第一个参数是匹配项,第二个参数是位置 
  8.  parseInt('1', 0) 
  9.  parseInt('2', 2)  //2进制中不可能有2 
  10.  parseInt('3', 4) 

eval用法

  1. function f() {} 
  2. var parent = Object.getPrototypeOf(f); 
  3. f.name // ? 
  4. parent.name // ? 
  5. typeof eval(f.name) // ? 
  6. typeof eval(parent.name) //  ?   

这段代码的执行结果?

  1. 答案:"f""Empty""function", error 
  2. 解析:f的函数名就是f 
  3.      parent是f原型对象的名字为"" , 
  4.      先计算eval(f.name) 为 f,f的数据类型是function 
  5.      eval(parent.name) 为undefined, "undefined" 

new Date()

  1. var a = new Date("2014-03-19"), 
  2. b = new Date(2014, 03, 19); 
  3. [a.getDay() === b.getDay(), a.getMonth() === b.getMonth()] 

这段代码的执行结果?

  1. 答案:[falsefalse
  2. 解析:var a = new Date("2014-03-19")    //能够识别这样的字符串,返回想要的日期 
  3.       Wed Mar 19 2014 08:00:00 GMT+0800 (CST) 
  4.       b = new Date(2014, 03, 19);       //参数要按照索引来 
  5.       Sat Apr 19 2014 00:00:00 GMT+0800 (CST) 
  6.       月是从0索引,日期是从1  
  7.       getDay()是获取星期几 
  8.       getMonth()是获取月份所以都不同 
  9. 巩固: [a.getDate() === b.getDate()] //true 

new Date() II

  1. var a = Date(0); 
  2. var b = new Date(0); 
  3. var c = new Date(); 
  4. [a === b, b === c, a === c] 

这段代码的执行结果?

  1. 答案:[falsefalsefalse
  2. 解析:当日期被作为构造函数调用时,它返回一个相对于划时代的对象(JAN 01 1970)。 
  3. 当参数丢失时,它返回当前日期。当它作为函数调用时,它返回当前时间的字符串表示形式。 
  4. a是字符串   a === b // 数据类型都不同,肯定是false 
  5. b是对象     b === c // 引用类型,比的是引用地址 
  6. c也是对象   a === c // 数据类型都不同,肯定是false 

new Date() III

  1. var a = new Date("epoch"

你认为结果是多少呢?

  1. 答案:Invalid Date {} 
  2. 解析:您得到“无效日期”,这是一个实际的日期对象(一个日期的日期为true)。但无效。这是因为时间内部保持为一个数字,在这种情况下,它是NA。 
  3.       在chrome上是undefined  
  4.       正确的是格式是var d = new Date(yearmonthday, hours, minutes, seconds, milliseconds); 

Function.length

  1. var a = Function.length, 
  2. b = new Function().length 
  3. a === b 

这段代码的执行结果是?

  1. 答案:false 
  2. 解析:首先new在函数带()时运算优先级和.一样所以从左向右执行 
  3.      new Function() 的函数长度为0 
  4. 巩固:function fn () { 
  5.          var a = 1; 
  6.       } 
  7.       console.log(fn.length)  
  8.       //0 fn和new Function()一样 
  • 要是看过往期的这篇文章[诚意满满✍]带你填一些JS容易出错的坑 就可以给我点个赞👍关注一下啦,下面的内容都是这篇文章的内容。

[1,2,5,10].sort()

不写回调函数的话,是按照什么排序呢?

JavaScript默认使用字典序(alphanumeric)来排序。因此结果是[1,10,2,5]

正确排序的话,应该[1,2,5,10].sort( (a,b) => a-b )

"b" + "a" + +"a" + "a"

你认为输出是什么?

上面的表达式相当于'b'+'a'+ (+'a')+'a',因为(+'a')是NaN,所以:

'b'+'a'+ (+'a')+'a' = 'b'+'a'+ "NaN"+'a'='baNaNa'

闭包

这是一个经典JavaScript面试题

  1. let res = new Array() 
  2.        for(var i = 0; i < 10; i++){ 
  3.            res.push(function(){ 
  4.                return console.log(i) 
  5.            }) 
  6.        } 
  7.        res[0]()  
  8.        res[1]() 
  9.        res[2]() 

期望输出的是0,1,2,实际上却不会。原因就是涉及作用域,怎么解决呢?

  • [x] 使用let代替var,形成块级作用域
  • [x] 使用bind函数。
  1. res.push(console.log.bind(null, i)) 

解法还有其他的,比如使用IIFE,形成私有作用域等等做法。

又一经典闭包问题

  1. function fun(n,o) { 
  2.   console.log(o) 
  3.   return { 
  4.     fun:function(m){ 
  5.       return fun(m,n); 
  6.     } 
  7.   }; 
  8. var a = fun(0);  a.fun(1);  a.fun(2);  a.fun(3);//undefined,?,?,? 
  9. var b = fun(0).fun(1).fun(2).fun(3);//undefined,?,?,? 
  10. var c = fun(0).fun(1);  c.fun(2);  c.fun(3);//undefined,?,?,? 

留给你们思考

隐式转换

  1. var a = [0]; 
  2. if (a) { 
  3.   console.log(a == true); 
  4. else { 
  5.   console.log("wut"); 

你们觉得答案是多少呢?这题涉及到隐式转换了,这个坑我自己的好好补一补

// 答案:false

再来一道?

  1. function fn() { 
  2.     return 20; 
  3. console.log(fn + 10); // 输出结果是多少 
  1. function fn() { 
  2.     return 20; 
  3. fn.toString = function() { 
  4.     return 10; 
  5. console.log(fn + 10);  // 输出结果是多少? 
  1. function fn() { 
  2.     return 20; 
  3.  
  4. fn.toString = function() { 
  5.     return 10; 
  6.  
  7. fn.valueOf = function() { 
  8.     return 5; 
  9.  
  10. console.log(fn + 10); // 输出结果是多少? 

说到底JS类型转换的好好补一补了

你真的理解操作符吗

  1. [1<2<3,3<2<1] 
  2. //[false,false
  3. //[true,true
  4. //[false,true
  5. //[true,false

选一个吧,比较操作符,赋值运算符优先级哪个更高呢?

0.1+0.2 !== 0.3 ?

面试的时候,问你这个问题,要是回答错误的话,估计面试官对基础很是怀疑!!!

问你这个题目的时候,你可以牵扯出很多问题,比如JS如何存储小数的呢?比如聊一聊二进制,比如实际开发中,遇到精度的问题,你是怎么解决的,你有什么好办法。

聊完这个,你可以牵扯出最大安全数,比如JavaScript的最大安全整数是多少,超出这个范围的话,怎么解决精度问题呢?

ES规范中新提出的BigInt解决了什么问题呢,你又发现了BigInt中哪些坑呢?

如何解决精度问题呢?

这里推荐Number-Precision库,不到1K的体积。

arguments

  1. function sidEffecting(ary) { 
  2.           ary[0] = ary[2]; 
  3.       } 
  4.       function bar(a, b, c) { 
  5.           c = 10 
  6.           sidEffecting(arguments); 
  7.           return a + b + c; 
  8.       } 
  9.       function demo (arg) { 
  10.           arg.name = 'new Name' 
  11.       } 
  12.       console.log(bar(2, 2, 2)) 

涉及到ES6语法,这题答案肯定都会做是22,但是呢,稍微改变一下题目,就比较坑了….

  1. function sidEffecting(ary) { 
  2.           ary[0] = ary[2]; 
  3.       } 
  4.       function bar(a, b, c = 4) { 
  5.           c = 10 
  6.           sidEffecting(arguments); 
  7.           return a + b + c; 
  8.       } 
  9.       function demo (arg) { 
  10.           arg.name = 'new Name' 
  11.       } 
  12.       console.log(bar(2, 2, 2)) 

这个答案是多少呢?根据MDN上对argument有更加准确的定义,看argument

  • 当非严格模式中的函数有包含剩余参数、默认参数和解构赋值,那么arguments对象中的值不会跟踪参数的值(反之亦然)。

找到这句话,bar函数存在默认参数,并且在非严格模式下,所以不会跟踪参数的值,自然结果就14

请读者细细体会

浏览器

  1. let demo1 = {class: "Animal"name'sheet'}; 
  2.       console.log(demo1.class) 

比较流氓,这个跟浏览器相关,class是保留字(现在的话,class是关键字),答案并不要紧,重要的是自己在取属性名称的时候尽量避免保留字. 如果使用的话请加引号 a['class']。

保留字vs关键字

个人理解的话,关键字就是有特殊含义的,不用用作变量名。比如

  1. let class = 123; 

现在看来肯定报错,那有什么需要我们注意的呢?

  1. let undefined = 123; 

这样子并不会报错,这个跟浏览器有点关系,这样子看来undefined不是关键字。所以为了保险起见,建议大家在判断一个变量是不是未定义的话,尽量使用void 0 === undefined 很有可能undefined会被当作是变量来赋值

void 0 值就是undefined

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

这个应该是经常遇见的题了,搞明白很简单,map函数怎么使用,parseInt函数怎么使用

关于Array数组的话,我之前写了一篇文章,从源码角度解析大部分方法

点进去重温一遍:[干货👍]从详细操作js数组到浅析v8中array.js

map接受两个参数,一个callback,一个this,即调用函数时this指向,其中callback回调函数是三个参数,一个currentValue,index,array;

parseInt接受两个参数:string,radix(基数)

返回NaN有两种情况

  • radix 小于 2 或大于 36 ,或
  • 第一个非空格字符不能转换为数字。
  • 当radix是0或者undefined时,又是特殊情况,具体异步MDN
  1. parseInt('1', 0); 
  2. parseInt('2', 1); 
  3. parseInt('3', 2); 

两者结合的话,结果自然很明显,[1,NaN,NaN]

Math.min() 为什么比 Math.max() 大?

  1. Math.min() < Math.max() // false 

按照常规思路的话,应该是true,毕竟最小值应该小于最大值,但是实际情况是false

原因:

  • Math.min 的参数是 0 个或者多个。如果是多个参数很容易理解,返回参数中最小的。
  • 如果是0个参数,或者没有参数,则返回 Infinity。
  • 而 Math.max() 没有传递参数时返回的是 -Infinity。

要是面试官问这个问题,额。。。。

[].concat[1,2,3]

输出是什么?注意不是[].concat([1,2,3])

  1. // [1,2,3] 
  2.  
  3. // Uncaught SyntaxError: .... 
  4.  
  5. // undefined 

答案是undefined,原因是什么呢?

第一步计算[].concat,结果是Array.prototype.concat

第二步执行一个逗号操作符,逗号操作符对它的每个操作对象求值(从左至右),然后返回最后一个操作对象的值。

  1. >1,2,3 
  2. 返回3 

第三步执行一个数组访问运算或属性访问运算

所以上面[].concat[1,2,3] 等价于Array.prototype.concat[3]

那么结果自然就是 undefined。

[1,2,NaN,3].indexOf(NaN)

//2 or -1

indexOf方法会进行严格相等判断

NaN !== NaN

怎么办呢?

  1. let realIsNaN = value => typeof value === 'number' && isNaN(value); 

先要判断类型,是因为字符串转换会先转换成数字,转换失败为 NaN。所以和 NaN 相等。

  1. isNaN('jjjj') —> true 

第二种方法

  1. let realIsNaN = value => value !== value; 

Number.isFinite & isFinite

  1. Number.isFinite('0') === isFinite('0'
  2.  
  3. Number.isFinite(0) === isFinite('0'

打印结果是什么,能不能具体说一说?

Number.isFinite()检测有穷性的值,唯一和全局isFinite()函数相比,这个方法不会强制将一个非数值的参数转换成数值,这就意味着,只有数值类型的值,且是有穷的(finite),才返回 true。

自然答案就是 false,true

一道容易被人轻视的面试题

  1. function Foo() { 
  2.     getName = function () { alert (1); }; 
  3.     return this; 
  4. Foo.getName = function () { alert (2);}; 
  5. Foo.prototype.getName = function () { alert (3);}; 
  6. var getName = function () { alert (4);}; 
  7. function getName() { alert (5);} 
  8.  
  9. //请写出以下输出结果: 
  10. Foo.getName(); 
  11. getName(); 
  12. Foo().getName(); 
  13. getName(); 
  14. new Foo.getName(); 
  15. new Foo().getName(); 
  16. new new Foo().getName(); 

push方法

  1. let newList = [1,2,3].push(4) 
  2. console.log(newList.push(4)) 

认为输出什么?

// Error

原因在于Array.prototype.push()返回的是新数组的长度,所以呢4.push(5)自然Error

自动分号插入

  1. function foo1() 
  2.  return { 
  3.      bar: "hello" 
  4.  }; 
  5.  
  6. function foo2() 
  7.  return 
  8.  { 
  9.      bar: "hello" 
  10.  }; 
  11. var a=foo1(); 
  12. var b=foo2(); 
  13. console.log(a) //Object {bar: "hello"
  14. console.log(b) //underfind 
  15. //仔细看就知道了 
  16. // 会在第10行加入一个`;` 

会在第10行自动加一个分号; 所以返回的就是undefined

let var

  1. function foo() { 
  2. let a = b = 0; 
  3. a++; 
  4. return a; 
  5. foo(); 
  6. typeof a; // => ??? 
  7. typeof b; // => ??? 

上面的let a = b = 0; 等价于 window.b = 0, let a = b;

眼力题

  1. const length = 4; 
  2. const numbers = []; 
  3. for (var i = 0; i < length; i++);{ 
  4.   numbers.push(i + 1); 
  5.  
  6. numbers; // => ??? 

唯一需要注意的就是for语句后面带了;沙雕题

加了;,会认为for执行完,所以指定的都是空语句,最后numbers为[5]

获取字符串中特定索引字符

  1. console.log('Hello World'[4]) 

使用的就是方括号表示法获取字符串特定索引的字符,值得注意的是,IE7低版本使用的是charAt()

所以这题输出o

!==

  1. const name = 'TianTianUp' 
  2. console.log(!typeof name === 'string'
  3. console.log(!typeof name === 'object'

typeof name 返回的是 ’string‘, 字符串’string‘是一个truthy值。因此!typeof name 返回一个布尔值false。所以

false === ’string'

和 false === ’object‘返回false

(检测一个类型的值话,我们应该使用 !==而不是!typeof)

forEach

  1. const nums = [1, 2, 3, 4, 5, 6]; 
  2. let firstEven; 
  3. nums.forEach(n => { 
  4.   if (n % 2 ===0 ) { 
  5.     firstEven = n; 
  6.     return n; 
  7.   } 
  8. }); 
  9. console.log(firstEven); 

唯一需要注意的就是forEach源码是怎么写的,看过源码的都知道,forEach使用return是不能中止循环的,或者说每一次调用callback函数,终止的是当前的一次,而不是整个循环。

结果自然就是6

 

责任编辑:姜华 来源: TianTianUp
相关推荐

2021-06-08 06:13:16

React开发开发技术

2021-06-30 07:19:35

微服务业务MySQL

2020-08-07 08:04:03

数据库MySQL技术

2018-06-08 08:50:35

编程语言并发编程

2013-12-24 14:50:39

Ember.js框架

2022-03-02 08:01:31

面试前端开发

2013-06-07 08:48:37

Android开发注意事项

2018-03-26 20:00:32

深度学习

2021-10-31 07:36:17

前端JavaScript编程

2019-03-28 13:50:47

大数据面试Hadoop

2020-01-15 15:07:48

JavaArrayList数据

2017-11-06 08:26:24

2015-11-23 10:16:12

2021-11-18 08:55:49

共享CPU内存

2022-06-08 08:03:51

React.jsReactJS 库

2021-05-27 09:27:35

开发技能缓存

2017-11-14 15:22:06

ReactNativeAppBugly

2020-02-03 16:03:36

疫情思考

2010-09-28 14:14:19

SQL语句

2016-11-16 21:18:42

android日志
点赞
收藏

51CTO技术栈公众号