hawx1993/tech-blog

你不知道的JavaScript

hawx1993 opened this issue · 0 comments

摘录自己平时遇到的比较重要的js相关的知识点,文章会随时不断更新。

按位非(~)以及双非(~~)的使用

// 双非遇到false的值都将转为0
~~false;   // 0
~~null;   // 0
~~0;    // 0
~~'';   // 0
~~NaN;   // 0
~~[];    // 0
~~{};  // 0

// 双重按位非(~~)对于数字的运算相当于Math.floor()
~~0.9 === 0;//true

// 对任一数值 x 进行按位非操作的结果为 -(x + 1),并向下取整
~3.9;  //-4
~0;  //-1

字符串数字大小的比较

'9' > '10';// true

字符串的比较是按字母排列顺序进行的比较,'1'字符排在字符'9'的前面,所以'9'大于'1'

计算精度问题

  • 为什么0.1 + 0.2不等于0.3?

因为计算机是二进制来表示浮点数的,无法准确表示一个浮点数,只能逼近。首先我们要了解浮点数二进制表示, 有以下两个原则:
1.整数部分对 2 取余然后逆序排列
2.小数部分乘 2 取整数部分, 然后顺序排列

这就引出了一个问题, 你永远不能存下 0.1 的二进制, 即使你把全世界的硬盘都放在一起, 也存不下 0.1 的二进制小数.

要判断两个浮点数是否相等,还是建议用逼近的比较.比如ES6新增了一个Math.EPSILON

0.1+0.2 - 0.3 < Number.EPSILON;// true

setTimeout 间隔输出

改写如下,使之间隔输出:

for (var i=1; i<=5; i++) { 
    setTimeout( function timer() {
        console.log(i);
    }, i*1000 );
}

setTimeout定时器执行时,会返回唯一的一个id,通常为数字。

1.借助循环闭包的特性,每次循环时,将i值保存在一个闭包中,当setTimeout中定义的操作执行时,则访问对应闭包保存的i值即可。

for (var i=1; i<=5; i++) { 
    (function(i) {
        setTimeout( function timer() {
            console.log(i);
        }, i*1000 );
    })(i)
}

2.利用let

for (let i=1; i<=5; i++) { 
	setTimeout( function timer() {
		console.log(i);
	}, i*1000 );
}

使用var,你拥有一个函数作用域,对于所有循环迭代只有一个共享绑定,即每个setTimeout回调中的i表示在循环迭代结束后最终等于5

for (var i = 1; i <= 3; i++) { 
    function timer() {
        console.log(i);
    }
    setTimeout( timer, i * 1000 );
}

然后我们将循环展开,三次执行过程的变化如下:

// 第一步: i = 1;
setTimeout( timer, 1 * 1000 );

// 第二步:i = 2;
setTimeout( timer, 2 * 1000 );

// 第三步 i = 3;
setTimeout( timer, 3 * 1000 );

由于setTimeout是异步的,在循环过程中, timer() 函数并未变化,也没有执行( 计时器还未开始 )。

使用let,你拥有一个块级作用域,当在for循环中使用时,你可以为每个迭代获得一个新的绑定。 即每个setTimeout回调中的i表示一个不同的变量,每个变量都有一个不同的值