Javascript几个常见的坑

本文介绍几个Javascript里经常遇到的一些坑。

一、console.log打印对象,折叠属性延时快照

        几乎所有的前端都要被这个问题坑一次,而且一旦踩到这坑到你爬出来,往往不下半小时。如果你还不知道这个问题,相信我,你将在某次调试中不经意间遇到它,所以你可以花三分钟了解一下。

        console.log是前端最常用的调试办法之一,其功能是打印一条消息到浏览器控制台。console.log的坑在于,其打印的变量内容,并非打印时的快照,这在我们查看打印值的时候会给我们带来巨大困扰。具体表现为:如果我们打印一个对象之后修改了对象属性值,这时候我们再点开对象的折叠属性,控制台显示该属性值的是修改后的值而非打印时刻的值!!!

示例:

let a = { b: { c: 1 } }
console.log(a)
a.b.c = 2

打印结果默认是一个属性折叠的对象:

我们展开打印结果:

打印a时,a.b.c的值是1,然而当我们把a展开却发现a.b.c的值变成了2!

实际上,console.log打印的对象属性值,取决于该对象第一次被展开是的值,而非打印时的值。

        

二、时间对象的方法getMonth()和getDay()

写一个简单的日期格式化函数,该函数接收一个时间戳和一个日期格式,返回按照指定格式格式化后的日期字符串:

function formatTime (time, format = 'yyyy-MM-dd') {
  const formatNum = num => String(num).padStart(2, '0')
  const date = new Date(time)
  return format.replace(/yyyy/g, date.getFullYear())
    .replace(/MM/g, formatNum(date.getMonth()))
    .replace(/dd/g, formatNum(date.getDate()))
}

我们本想将yyyy、MM、dd分别替换为年、月、日,运行代码后发现,年、日正常转换了,而月份却出现了异常。今天是2020年3月24日,调用上述函数:

打印的时间居然是“2020年02月24日”,月份少了1。原来,getMonth返回基于0的值,即0 代表一月份,1 代表二月份, 2 代表三月份,依此类推。作为程序员而言,一个序列从0开始应该还是可以接受(毕竟许多语言的数组下标都是从0开始的)。然而在日期这里,getDate返回1~31的数字,表示一个月中的哪一日,而getMonth却返回0~11中的一个数字,这二者的不一致性确实不太科学。

另外一个有着相似坑的函数是getDay,它可以获取当前日期是本周的周几,其返回值也是从0开始的,不过0代表周日,1代表周一,依此类推:

三、sort默认排序

sort是JS里用来排序的函数,默认是升序排序,不过这里的“升序”与我们的认知略有不同。这个坑最常见于数字排序,先来一个简单的排序:

数组升序排序了,很方便吧,再来一个

 很明显并不是我们所期望的升序。MDN对于sort的描述:如果没有指明 compareFunction ,那么元素会按照转换为的字符串的诸个字符的Unicode位点进行排序。所以在对字符串排序时,会先将元素转为字符串,再排序。因为字符‘1’出现在‘3’, ‘5’, ‘7’之前,所以13被排在了这三个数字以前。

所以通常使用sort的时候,我们要注意给sort传递一个比较函数:

四、比较不能传递

假设又一个值value,我们想在它在某个区间[min, max]之间时执行某个逻辑,我们有可能在不经意间写出下面这样的代码:

if (min <= value <= max) {
  // xxx
}

然而不幸的是,JS中上述代码是不能正常工作的,因为JS的比较不能传递

为什么4 > 3 > 2是false呢?因为4 > 3 > 2相当于(4 > 3) > 2,即true > 2,这里会进行类型转换,true转为1,所以结果就是false。

(未完)

¥赞赏