一些零碎的笔记

运算符

今天在一个公众号文章里看到一道题目:

1
2
'5' + 3
'5' - 3

输出结果会是什么呢?我在控制台试了一下,结果是:

1
2
'5' + 3 // => '53'
'5' - 3 // => 2

在 MDN 上复习了一下相关知识点。

加法运算符的作用是数值求和,或者字符串拼接。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Number + Number -> 数字相加
1 + 2 // 3
// Boolean + Number -> 数字相加
true + 1 // 2
// Boolean + Boolean -> 数字相加
false + false // 0
// Number + String -> 字符串连接
5 + "foo" // "5foo"
// String + Boolean -> 字符串连接
"foo" + false // "foofalse"
// String + String -> 字符串连接
"foo" + "bar" // "foobar"

我自己的理解是:转换类型的优先级 Boolean < Number < String,布尔值与布尔值或数字相加,布尔值都先转换成数字,再做加法;数字和字符串相加,数字转换成字符串,再进行字符串的拼接。

JS 运算符,除了加法有类型转换的歧义外,其他减、乘、除、求余运算都会先转换运算符两边的类型为 Number 后再做运算。

特殊值

JavaScript 总共有 7 种数据类型:

  • 基本数据类型:number,string,boolean

  • 复合数据类型:object(对象,数组,还有一些专用对象如:Date,Error,RegExp)

  • 函数数据类型:function

  • 特殊数据类型:null,undefined

Number 类型包括两个特殊值:NaN 和 Infinity。

NaN:当一个运算产生了未定义的结果或该运算发生错误,则返回一个非数字的特殊值 NaN。

1
2
3
var num = 0/0;
console.log(num); // => NaN
"foo" - 3; // => NaN

NaN 不和任何数值相等,包括它本身。这一点可以用来判断一个值是否为 NaN。

Infinity:当一个浮点数超过了 JavaScript 所能表示的最大值时,其结果为一个特殊的无穷大值Infinity。

1
2
3
4
5
6
7
var a = 9e999999;
console.log(a); // => Infinity
Infinity * 0 // => NaN
Infinity * Infinity // => Infinity
2.0 / 0 // => Infinity
2.0 / 0.0 // => Infinity
2.0 / -0.0 // => -Infinity

JS 的特殊数据类型包括 null 和 undefined。

null:表示无值,有别于其他所有值, 如果一个变量的值为 null,表示该变量的值不是一个有效的对象(数字/字符串…)。
注意:JavaScript 中,typeof 运算符将报告 null 值为 Object 类型,而非 null 类型,这点潜在的混淆是为了向下兼容

undefined 表示:1、未定义的数据 2、定义未赋值的数据 3、不存在的属性

1
2
3
var a;
console.log(a); // => undefined
console.log(Math.abcdef); // => undefined

typeof 运算符将 Date 和 Array 都认为是 Object 类型,要区分可用对象的 constructor 属性

1
2
3
4
var str = "123";
console.log(str.constructor == String); // => true
var array = [1,2,3];
console.log(array.constructor == Array); // => true

也可以使用 instanceof 关键字

1
2
var date = new Date();
console.log(date instanceof Date); // => true

精度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 加法 =====================
// 0.1 + 0.2 = 0.30000000000000004
// 0.7 + 0.1 = 0.7999999999999999
// 0.2 + 0.4 = 0.6000000000000001
// 2.22 + 0.1 = 2.3200000000000003
// 减法 =====================
// 1.5 - 1.2 = 0.30000000000000004
// 0.3 - 0.2 = 0.09999999999999998
// 乘法 =====================
// 19.9 * 100 = 1989.9999999999998
// 19.9 * 10 * 10 = 1990
// 1306377.64 * 100 = 130637763.99999999
// 1306377.64 * 10 * 10 = 130637763.99999999
// 0.7 * 180 = 125.99999999999999
// 9.7 * 100 = 969.9999999999999
// 39.7 * 100 = 3970.0000000000005
// 除法 =====================
// 0.3 / 0.1 = 2.9999999999999996
// 0.69 / 10 = 0.06899999999999999

在 JavaScript 中整数和浮点数都属于 Number 数据类型,所有数字都是以 64 位浮点数形式储存,即便整数也是如此。
计算机是按照二进制来处理数的,所以小数也是转换为二进制来计算的,且 JS 采用的是 64 位双精度浮点数,支持小数最多到 53 位,而且很多小数的二进制都是无限循环小数。
但控制台输出结果,0.2-0.1 的确是 0.1,动笔计算一下过程验证一下:0.2 二进制为 0.00110011…001101,0.1 二进制为 0.000110011…001101,其实看出来 0.2 的二进制相对于 0.1 的二进制是做了 1 位的位移,二进制相减的结果整好和减数的二进制相等,也就是 0.2(二进制) - 0.1(二进制) = 0.1(二进制)。小数相减 0.8-0.4,0.6-0.3 这一类都是这样,二进制运算与数学运算结果恰好相等。