Open yoowinsu opened 7 years ago
本文首发在个人博客yoowin.me
[0,1,10,11,8,-2].sort(); //[[-2, 0, 1, 10, 11, 8]
sort()默认情况下会按照Unicode码点排序,而不是数值顺序排序,所以正确的解决方案为:
sort()
[0,1,10,11,8,-2].sort((a,b)=>a-b); //[[-2, 0, 1, 8, 10, 11]
先看如下代码
0.1 + 0.2 === 0.30000000000000004 //true 1000000000000000128 === 1000000000000000129 //true
本质上这是二进制浮点数造成的精度丢失问题,这种问题也存在于除JavaScript之外的其他语言中,可以参考0.30000000000000004.com 因为计算机只能读懂二进制数值,我们看下0.1和0.2转换成二进制:
0.1 => 0.0001 1001 1001 1001…(无限循环) 0.2 => 0.0011 0011 0011 0011…(无限循环)
双精度浮点数的小数部分最多支持 52 位,所以计算后会进行小数位的限制截断,也就造成了舍入误差,再次转换成十进制后就是我们所看到的0.30000000000000004
解决方法
(0.1+0.2).toFixed(1) //"0.3" (0.1+0.2).toFixed(2) //"0.30"
toFixed()方法是保留小数后面的位数是几位,注意:得到的结果是字符串
toFixed()
var b = 0; function fn() { var a = b = 3; } fn() console.log(b); //3
一般会有不少人觉得应该打印0,因为b=3是函数内声明,属于局部变量。
这里var a=b=3是个坑,赋值运算是从右往左的,所以这里的b=3是全局变量。
var a=b=3
所以声明变量建议单个单个的来。
if(d){ var d = 5; } console.log(d) //undefined
因为预解析的原因,所以var d的代码会提升到代码顶部,且值为undefined,然后执行流程语句,因为d为undefined,转为布尔值为false,所以不会进入if判断语句,所以打印结果为undefined
var d
下面的代码也是同理
if(!('d' in window)){ var d = 5; } console.log(d) //undefined
function foo() { console.log('1') } foo() //2 function foo() { console.log('2') } foo() //2
匿名函数的预解析会把函数提升到函数所在作用域的顶部,声明先于调用,而第二个foo函数会覆盖第一个foo函数的声明,所以两次foo()的调用都是在执行第二个声明的函数,所以打印两次2
foo()
var getName = function(){ console.log(2); } function getName (){ console.log(1); } getName(); //2
匿名函数会预解析,但是函数表达式不会预解析。 所以匿名函数getName会提升到所在作用域顶部,然后依次执行代码,执行到函数表达式时,getName函数表达式会覆盖匿名函数getName,所以打印结果是2
function fn2(){ var a = 666; fn1() } fn2() //undefined function fn1(){ console.log(a); } var a = 333;
匿名函数fn1会提前预解析,提升到作用域顶部。 a变量也会提升到代码顶部并初始化值为undefined。 执行fn2。调用fn1是执行fn1函数,而fn1执行时a只和fn1所在作用域有关,调用时a只是初始化,还未赋值为333,所以打印结果为undefined
null == undefined //true
请记住这个特殊情况吧! 所以我建议写代码判断相等用=== 还有null和undefined的区别
===
null表示"没有对象",即该处不应该有值。 undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。
console.log(Math.max()) //-Infinity console.log(Math.min()) //+Infinity console.log(Math.min()>Math.max()) //true
typeof(null)==='object' //true
这是错的,虽然他返回的结果是true,但这是JavaScript设计的错误,考虑到后兼容,就保持了这一错误
let x = 5; let y = 1<!--x;
上面的代码之后x和y的值是多少? 答案是5和1. 因为<!--会把后面的代码注释掉(虽然是HTML注释,但这里浏览器依然会当做注释),所以后面的代码都是不影响y的值的,就像下面代码
<!--
let z = 8<!--你好#¥#%¥……456--> console.log(z) //8
哪怕是浏览器不能识别,会报错的字符依然不受影响,因为浏览器会跳过注释执行代码
var young = {name: 'su'} var old = {age: 66} function fn(a,b){ a.name = 'yoowin' b = {age: 20} } fn(young,old) console.log(young) console.log(old)
这道代码题最开始我疑惑了挺久,在网上也有搜过,貌似对于值传递一直有争议,我自己刚开始也不是很明白。 先看下答案:
var young = {name: 'su'} var old = {age: 66} function fn(a,b){ a.name = 'yoowin' b = {age: 20} } fn(young,old) console.log(young) //{name: "yoowin"} console.log(old) //{age: 66}
现在我认为的是实参是原始类型的话,其对于形参是值传递,是值的拷贝;实参是引用类型的话,其对于形参是引用传递,形参的指针指向实参指针对应的对象。
在看题目中,重点就在于fn函数中, 执行的第一行是通过指针把对象的属性改变了,则原对象是会改变的,所以打印的young值也确实改变了; 执行的第二行中,本来形参b的指针指向{age: 66},然后 b = {age: 20}的赋值语句把b的指针改变了,指向了{age: 20},所以实参old对应的对象并没有改变,依然是{age: 66},所以会打印{age: 66}
{age: 66}
b = {age: 20}
{age: 20}
数组排序问题
sort()
默认情况下会按照Unicode码点排序,而不是数值顺序排序,所以正确的解决方案为:0.1+0.2 !== 0.3的问题
先看如下代码
本质上这是二进制浮点数造成的精度丢失问题,这种问题也存在于除JavaScript之外的其他语言中,可以参考0.30000000000000004.com 因为计算机只能读懂二进制数值,我们看下0.1和0.2转换成二进制:
双精度浮点数的小数部分最多支持 52 位,所以计算后会进行小数位的限制截断,也就造成了舍入误差,再次转换成十进制后就是我们所看到的0.30000000000000004
解决方法
toFixed()
方法是保留小数后面的位数是几位,注意:得到的结果是字符串全局变量问题
一般会有不少人觉得应该打印0,因为b=3是函数内声明,属于局部变量。
这里
var a=b=3
是个坑,赋值运算是从右往左的,所以这里的b=3是全局变量。所以声明变量建议单个单个的来。
变量提升问题
因为预解析的原因,所以
var d
的代码会提升到代码顶部,且值为undefined,然后执行流程语句,因为d为undefined,转为布尔值为false,所以不会进入if判断语句,所以打印结果为undefined下面的代码也是同理
匿名函数预解析1
匿名函数的预解析会把函数提升到函数所在作用域的顶部,声明先于调用,而第二个foo函数会覆盖第一个foo函数的声明,所以两次
foo()
的调用都是在执行第二个声明的函数,所以打印两次2匿名函数预解析2
匿名函数会预解析,但是函数表达式不会预解析。 所以匿名函数getName会提升到所在作用域顶部,然后依次执行代码,执行到函数表达式时,getName函数表达式会覆盖匿名函数getName,所以打印结果是2
匿名函数预解析3
匿名函数fn1会提前预解析,提升到作用域顶部。 a变量也会提升到代码顶部并初始化值为undefined。 执行fn2。调用fn1是执行fn1函数,而fn1执行时a只和fn1所在作用域有关,调用时a只是初始化,还未赋值为333,所以打印结果为undefined
null和undefined
请记住这个特殊情况吧! 所以我建议写代码判断相等用
===
还有null和undefined的区别Math.min>Math.max()
typeof(null)==='object'
这是错的,虽然他返回的结果是true,但这是JavaScript设计的错误,考虑到后兼容,就保持了这一错误
JavaScript注释
上面的代码之后x和y的值是多少? 答案是5和1. 因为
<!--
会把后面的代码注释掉(虽然是HTML注释,但这里浏览器依然会当做注释),所以后面的代码都是不影响y的值的,就像下面代码哪怕是浏览器不能识别,会报错的字符依然不受影响,因为浏览器会跳过注释执行代码
JavaScript函数中参数的传递
这道代码题最开始我疑惑了挺久,在网上也有搜过,貌似对于值传递一直有争议,我自己刚开始也不是很明白。 先看下答案:
现在我认为的是实参是原始类型的话,其对于形参是值传递,是值的拷贝;实参是引用类型的话,其对于形参是引用传递,形参的指针指向实参指针对应的对象。
在看题目中,重点就在于fn函数中, 执行的第一行是通过指针把对象的属性改变了,则原对象是会改变的,所以打印的young值也确实改变了; 执行的第二行中,本来形参b的指针指向
{age: 66}
,然后b = {age: 20}
的赋值语句把b的指针改变了,指向了{age: 20}
,所以实参old对应的对象并没有改变,依然是{age: 66}
,所以会打印{age: 66}