JS笔记之JS数据类型(一)

原始类型的方法

在JS中允许我们像使用对象一样使用原始类型(数字。字符串等)。

1 字符串与对象的基本区别

一个原始值:

  • 是原始类型中的一种值。
  • 在 JavaScript 中有 7 种原始类型:stringnumberbigintbooleansymbolnullundefined

一个对象:

  • 能够存储多个值作为属性。
  • 可以使用大括号 {} 创建对象,例如:{name: "John", age: 30}。JavaScript 中还有其他种类的对象,例如函数就是对象

1.1 如何解决使原始类型拥有和对象类似的方法?

  1. 原始类型仍然是原始的。与预期相同,提供单个值。
  2. JavaScript 允许访问字符串,数字,布尔值和 symbol 的方法和属性。
  3. 为了使它们起作用,创建了提供额外功能的特殊“对象包装器”,使用后即被销毁。

所以原始类型可以提供方法,但它们依然是轻量级的。

JavaScript 引擎高度优化了这个过程。它甚至可能跳过创建额外的对象。但是它仍然必须遵守规范,并且表现得好像它创建了一样。

null/undefined 没有任何方法

特殊的原始类型 nullundefined 是例外。它们没有对应的“对象包装器”,也没有提供任何方法。从某种意义上说,它们是“最原始的”。

尝试访问这种值的属性会导致错误:alert(null.test); // error

2 数字类型

在现代的JS中数字有两种类型:

  • JS中常规的数字以64为的格式存储,也称为双精度浮点数,是我们大多数使用时数字。但是不能安全地超过 (253-1) 或小于 -(253-1)
  • BigInt 表示任意长度的整数,仅在少数特殊领域才会用到 BigInt。

2.1 编写数字的方式

你如要写一个10亿的数字:let billion = 1000000000 也可以使用下划线作为分隔符 let billiion = 1_000_000_000

这里的下划线 _ 扮演了“语法糖”的角色,使得数字具有更强的可读性。JS引擎会直接忽略数字之间的 _,所以 上面两个例子其实是一样的。

在 JS 中,我们可以通过在数字后面附加字母 "e" 并指定零的个数来缩短数字:

1
2
3
let billion = 1e9;  // 10 亿,字面意思:数字 1 后面跟 9 个 0

alert( 7.3e9 ); // 73 亿(与 7300000000 和 7_300_000_000 相同)

换句话说,e 把数字乘以 1 后面跟着给定数量的 0 的数字。

1
2
1e3 === 1 * 1000; // e3 表示 *1000
1.23e6 === 1.23 * 1000000; // e6 表示 *1000000

现在让我们写一些非常小的数字。例如,1 微秒(百万分之一秒):

1
let mcs = 0.000001;

就像以前一样,可以使用 "e" 来完成。如果我们想避免显式地写零,我们可以这样写:

1
let mcs = 1e-6; // 1 的左边有 6 个 0

2.2 十六进制、八进制和二进制数字

十六进制 在JS中总是表示颜色,使用0x 表示,二进制使用0b表示,八进制使用0o表示。只有这三种进制支持这种写法,其他的进制使用 parseInt 表示。

2.3 toString(base)

方法toString(base)方法,返回在给定base进制数字系统(base的范围可以从2到36。默认情况下是10)中num的字符串表示形式。

1
2
3
let num= 255;
console.log{num.toString(16)} // ff
console.log{num.tostring(2)} // 11111111

常用的进制范例:

  1. base=16 用户十六进制颜色,字符编码等,数字可以是0..9 或者是A..F。
  2. base=2 主要用于调试按位操作。数字是0和1。
  3. base=36 是最大进制,数字可以是0..9或者A..Z,所有的字母都被用于表示数字,对于36进制来说、一个;例字设计:将一个较长的数字标识符转化较短的时候,比如短连接,可以使用基数为36的数字系统表示。console.log( 123456..toString(36) ); // 2n9c

在范例第三点中 123456..toString(36) 两个点不是错误。如果想直接在一个数字上,调用一个方法,比如上面的例字中的toString,那么需要在数字后面加上两个点 .. 。

如果放置一个点,123456.toString(36)那么就会出现一个error,因为JS语法隐含了第一个点后面的部分是小数部分,如果再放一个点,那么JS就知道小数部分为空。

也可以写成(123346).toString(36)

2.4 舍入

舍入是对数字比较常用的操作之一。一下是几个对数字进行舍入操作的内建函数。

Math.floor:向下舍入, 3.1 变成 3,-1.1 变成 -2。

Math.ceil:向下舍入,3.1 变成 4,-1.1 变成 -1。

Math.round:像最近的整数舍入。3.1 变成 3,3.6 变成 4,3.5 变成 4。

Math.trunc:(IE浏览器不支持)移除小数点后的内容而不舍入。3.1 变成 3,-1.1 变成 -1。

2.5 保留小数位数

toFixed(n) 将数字输入到下小数的后n位,以字符串的形式返回结果。会向上或者向下的舍入到近似的值,类似Math.round()。如果小数部分比需要的短,则在末尾加0。 可以使用一元符号或者Number()将其转化为数字。例如:+num.toFixed(5)

2.6 不精确的计算

数字内部是以64为存储数字的,所以:其中52位被用于存储这些数字,11为被存储与小数点的位置,一位用于符号,如果一个数字很大,可能会溢出64位存储,变成一个特殊的值:infinty。

1
console.log(1e500);

在大多数语言中都会有精度的问题,console.log( 0.1 + 0.2 ); // 0.30000000000000004,

出现的原因:数字是以二进制存储在内存中,一个 1 和 0 的序列。但是在十进制数字系统中看起来很简单的 0.10.2 这样的小数,实际上在二进制形式中是无限循环小数。

其中的解决办法有:

  • 通过将数字舍入到最接近的可能数字来解决此问题,使用toFixed +(0.1 + 0.2 ).toFixed(2)

  • 使用乘法或者除法来减少误差。但是乘法除法只能减少误差,不能消除误差。

    1
    2
    alert( (0.1 * 10 + 0.2 * 10) / 10 ); // 0.3
    alert( (0.28 * 100 + 0.14 * 100) / 100); // 0.4200000000000001

    实际上完全处理小数是不可能的,但是我们可以在满足条件的情况下,减掉尾巴,来进行四舍五入即可。

2.7 isFinite和isNaN

infinity和-infinity以及NaN 都属于Number类型,但不是普通的数字。

  • isNaN() 将参数转化为数字,并判断其是否为NaN。

    为什么不用 xx === NaN?因为在JS中,NaN是独一无二的,即使是NaN === NaN 进行比较也是false。

  • isFinity() 将参数转为数字, 判断是否为常规数字。如果是常规数字而不是NaN、infinity,-infinity 返回true。

    1
    2
    3
    console.log( isFinite("15") ); // true
    console.log( isFinite("str") ); // false,因为是一个特殊的值:Na
    console.log( isFinite(Infinity) ); // false,因为是一个特殊的值:Infinity

    请注意,在所有数字函数中,包括 isFinite,空字符串或仅有空格的字符串均被视为 0

与Object.is 进行比较。它类似于 === 一样对值进行比较,但是他对于两种边缘庆魁昂更可靠。

1.它适用于NaN:Object.is(NaN, NaN) === true

2.值0和-0是不同的,Object.is(0, -0) === False,从技术上讲是对的,因为在内部数字的符号位可能会不同,即使其他的均为0。

在所有情况下, Objet.is(a, b) 与 a === b 相同。

2.8 parseInt 和 parsrFloat

使用一元运算符将字符串转化为数字时,是严格的,当转化的字符串不是一个数字时就会失败。(除了字符开头结尾的空格)

1
console.log(+"sss")  // NaN	

在现实中我们会经常遇到带有单位的字符串, 100px, 100pt,19€(欧元)。

parseInt 和 parsrFloat 他们可以从字符串中提取数字,,直到无法读取为止,如果发生error则返回收集到的数字,函数parseInt 返回一个整数,parseFloat 返回一个浮点数。

1
2
3
4
5
console.log( parseInt('100px') ); // 100
console.log( parseFloat('12.5em') ); // 12.5

console.log( parseInt('12.3') ); // 12,只有整数部分被返回了
console.log( parseFloat('12.3.4') ); // 12.3,在第二个点出停止了读取

parseInt 和 parsrFloat 的局限性:只能是数字开头的字符串,如果第一个字符就不是数字则无法读取,返回NaN。

1
console.log('xxx111') // NaN

parseInt(str,radix) radix:技术的意思, 第二个参数制定了数字系统的基数,因此parseInt 还可以解析十六进制,八进制,二进制等字符串。

1
2
3
4
alert( parseInt('0xff', 16) ); // 255
alert( parseInt('ff', 16) ); // 255,没有 0x 仍然有效

alert( parseInt('2n9c', 36) ); // 123456

2.9 其他的数学函数

Math 对象包含了一个小型的数学函数和常量库。

  • Math.random() 返回一个从 0 到 1 的随机数(不包括 1)。
  • Math.max(a, b, c…) 和 Math.min(a, b, c…) 从任意数量的参数中返回最大值和最小值。
  • Math.pow(n, power) 返回 n 的给定(power)次幂。

3 总结

要写很多0的数字

  • 有很多0的整数,将e和0的个数写到数字的后面。 123e5 === 12300000
  • 有很多0的小数,将e和0的个数写到数字的后面,0的个数前加上负号-,1.33e-5 === 0.0000133

3.2 不同的数字系统

  • 可以在十六进制,八进制,二进制 数字系统中写入数字。
  • parseInt(str, base) 将字符串 str 解析为在给定的 base 数字系统中的整数,2 ≤ base ≤ 36
  • num.toString(base) 将数字转化为给定的base数字系统中的字符串。

3.3 对于常规的数字检测

  • isNaN(value) 将参数转为为数字,并判断是否为NaN。
  • isFinite(value) 将其参数转换为数字,如果它是常规数字,则返回 true,而不是 `NaN/Infinity/-Infinity

3.4 将字符串转为数字

  • 使用一元符号,但是是严格模式。
  • 使用parseInt/parseFloat进行“软”转换,它从字符串中读取数字,然后返回在发生 error 前可以读取到的值。

3.5 小数

  • 使用 Math.floorMath.ceilMath.truncMath.roundnum.toFixed(precision) 进行舍入。
  • 使用小数时损失精度。