1、意外的全局变量
在以下代码中,typeof a 和 typeof b的值分别是什么:
function foo() {
let a = b = 0;
a++;
return a;
}
foo();
typeof a; // => ???typeof b; // => ???
答案:让我们仔细看看第2行:let a = b = 0。这个语句确实声明了一个局部变量a。但是,它也声明了一个全局变量b。
注:b是一个偶然创建的全局变量。
在浏览器中,上述代码相当于:
function foo() {
let a; window.b = 0; a = window.b; a++;
return a;
}
foo();
typeof a; // => 'undefined'
typeof window.b; // => 'number'
typeof a是 'undefined'。变量a仅在 foo()范围内声明,在外部范围内不可用。
typeof b等于'number'。b是一个值为 0的全局变量。
2、鹰眼测试
numbers 数组内容是什么:
const length = 4;
const numbers = [];
for (var i = 0; i < length; i++);{
numbers.push(i + 1);
}
numbers; // => ???
答案:上述代码中,我们可以清晰的看到 花括号 { 左侧的分号 ;,而它创建了一个空语句,空语句是不做任何事情的。
所以 for循坏执行了4次,仅仅是改变了 i 的值。
也就是:
const length = 4;
const numbers = [];
var i;
for (i = 0; i < length; i++) {
// does nothing
}
{
// a simple block
numbers.push(i + 1);
}
numbers; // => [5]
for()递增变量i直到4。然后JavaScript 进入代码块 { numbers.push(i + 1); },将4 + 1 添加到numbers数组中。
这样 numbers 就是 [5]。
3、自动插入分号
arrayFromValue() 返回什么值?
function arrayFromValue(item) {
return
[item];
}
arrayFromValue(10); // => ???
答案:很容易忽略关键词 return 和 表达式[item]之间的换行;
换行使JavaScript自动在 return和[items]表达式之间插入一个分号。
即:
function arrayFromValue(item) {
return;
[items];
}
arrayFromValue(10); // => undefined
函数中的 return; 导致它返回 undefined。
因此 arrayFromValue(10) 的值是 undefined 。
查看 https://dmitripavlutin.com/7-tips-to-handle-undefined-in-javascript/#24-function-return-value 阅读更多关于自动插入分号的内容。
4、闭包
下面脚本会在控制台输出什么:
let i;
for (i = 0; i < 3; i++) {
const log = () => {
console.log(i); }
setTimeout(log, 100);
}
答案:
我第一次做的时候,答案是 0,1和2,后来控制台调试发现是错的。
执行这个代码段分两个步骤。
步骤 1
1、for()迭代3次。在每次迭代过程中,都会创建一个新的函数log(),它捕获变量 i。然后setTimout()执行log()。
2、当for()循环完成时,i变量的值为3。
log()是一个捕获变量 i 的闭包,它在for()循环的外部作用域定义。重要的是要理解闭包从词法上捕获了变量 i 。
步骤 2
第2步在 100 毫秒后发生:
setTimeout()调用了队列中的3个log() 回调。log() 读取变量 i的当前值,即3,并记录到控制台3。
这就是为什么控制台输出3, 3 和3。
5、浮点数问题
等号判断的结果是什么:
0.1 + 0.2 === 0.3 // => ???
答案:首先我们看一下 0.1+0.2的值

0.1 和 0.2 的和 不完全等于 0.3,而是略大于 0.3。
由于浮点数在二进制中的编码机制,像浮点数的加法这样的操作会受到舍入误差的影响。
简单地说,直接比较浮点数是不精确的。
因此 0.1 + 0.2 === 0.3 是 false。
更多示例:

6、变量的提升