0x01 变量提升
JavaScript 引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部,这就叫做变量提升(hoisting)。
console.log(a);
var a = 1;
上面代码首先使用console.log方法,在控制台(console)显示变量a的值。这时变量a还没有声明和赋值,所以这是一种错误的做法,但是实际上不会报错。因为存在变量提升,真正运行的是下面的代码。
var a;
console.log(a);
a = 1;
最后的结果是显示undefined,表示变量a已声明,但还未赋值。
0x02 为什么有些人常量写在运算符左边
var x = 1;
var y = 2;
if (x = y) {
console.log(x);
}
// "2"
上面代码的原意是,当x等于y的时候,才执行相关语句。但是,不小心将严格相等运算符写成赋值表达式,结果变成了将y赋值给变量x,再判断变量x的值(等于2)的布尔值(结果为true)。
这种错误可以正常生成一个布尔值,因而不会报错。为了避免这种情况,有些开发者习惯将常量写在运算符的左边,这样的话,一旦不小心将相等运算符写成赋值运算符,就会报错,因为常量不能被赋值。
if (x = 2) { // 不报错
if (2 = x) { // 报错
0x03 object(对象)
对象是最复杂的数据类型,又可以分成三个子类型。
- 狭义的对象(object)
- 数组(array)
- 函数(function)
狭义的对象和数组是两种不同的数据组合方式。函数其实是处理数据的方法,JavaScript 把它当成一种数据类型,可以赋值给变量,这为编程带来了很大的灵活性,也为 JavaScript 的“函数式编程”奠定了基础。
引用
引用只局限于对象,如果两个变量指向同一个原始类型的值。那么,变量这时都是值的拷贝。
0x04 number
整数和浮点数
JavaScript 内部,所有数字都是以64位浮点数形式储存,即使整数也是如此。所以,1与1.0是相同的,是同一个数。
1 === 1.0 // true
这就是说,JavaScript 语言的底层根本没有整数,所有数字都是小数(64位浮点数)。容易造成混淆的是,某些运算只有整数才能完成,此时 JavaScript 会自动把64位浮点数,转成32位整数,然后再进行运算
由于浮点数不是精确的值,所以涉及小数的比较和运算要特别小心。
0.1 + 0.2 === 0.3
// false
0.3 / 0.1
// 2.9999999999999996
(0.3 - 0.2) === (0.2 - 0.1)
// false
正0和负0
几乎所有场合,正零和负零都会被当作正常的0。
唯一有区别的场合是,+0或-0当作分母,返回的值是不相等的。
(1 / +0) === (1 / -0) // false
上面的代码之所以出现这样结果,是因为除以正零得到+Infinity,除以负零得到-Infinity,这两者是不相等的(关于Infinity详见下文)。
NaN
NaN是 JavaScript 的特殊值,表示“非数字”(Not a Number),主要出现在将字符串解析成数字出错的场合。
需要注意的是,NaN不是独立的数据类型,而是一个特殊数值,它的数据类型依然属于Number,使用typeof运算符可以看得很清楚。
Infinity
Infinity表示“无穷”,用来表示两种场景。一种是一个正的数值太大,或一个负的数值太小,无法表示;另一种是非0数值除以0,得到Infinity。
// 场景一
Math.pow(2, 1024)
// Infinity
// 场景二
0 / 0 // NaN
1 / 0 // Infinity
上面代码中,第一个场景是一个表达式的计算结果太大,超出了能够表示的范围,因此返回Infinity。第二个场景是0除以0会得到NaN,而非0数值除以0,会返回Infinity。
Infinity有正负之分,Infinity表示正的无穷,-Infinity表示负的无穷。
Infinity === -Infinity // false
1 / -0 // -Infinity
-1 / -0 // Infinity
上面代码中,非零正数除以-0,会得到-Infinity,负数除以-0,会得到Infinity。
由于数值正向溢出(overflow)、负向溢出(underflow)和被0除,JavaScript 都不报错,所以单纯的数学运算几乎没有可能抛出错误。
Infinity大于一切数值(除了NaN),-Infinity小于一切数值(除了NaN)。
Infinity > 1000 // true
-Infinity < -1000 // true
Infinity与NaN比较,总是返回false。
Infinity > NaN // false
-Infinity > NaN // false
Infinity < NaN // false
-Infinity < NaN // false