js基石之Number:应用(数字运算,数字&字符串转换,不同进制表示&相互转换)

101 阅读6分钟

相关文章

js基石之数据类型一:类型分类&区别
js基石之数据类型二:类型判断
js基石之数据类型三:类型转换
js基石之Number:本质
js基石之Number:应用(数字运算,数字&字符串转换,不同进制表示&相互转换)
js基石之字符: ASCII,GBK,Unicode,utf-32,utf-16,utf-8,encodeuri,encodeuricomponent,base64
js基石之Symbol值
js基石之Object,Map,WeakMap
js基石之Array,Stack,Queue,Set,WeakSet

本文主要介绍js中的数字系列,包括Number,Math,BigInt等对象以及经常用到的parseInt,parseFloat,toString,valueOf在数字的应用场景中有什么区别.

主要围绕三个场景:

1:数字运算(大数运算,浮点数运算)
2:数字&字符串转换
3:数字的不同进制表示&相互转换

Number

Number构造:

  • 作为构造函数调用, 创建Number对象 这个对象不是原始值
  • 作为普通函数调用 将其他类型转换为数字类型, 结果有两种成功 NaN
const b = Number("123");
console.log(b) // 123

const a = Number("123a");
console.log(a) // NaN

不存在一部分解析成功.

parseInt:

  1. 尽可能多的将输入解析为一个整数,结果有三种 成功 部分成功 NaN
Number.parseInt('121') // 121 成功
Number.parseInt('121abc') // 121 部分成功
Number.parseInt('121.1abc') // 121 部分成功
Number.parseInt('a111') // NaN
  1. 进制转换

关于parseInt的参数需要注意下 尤其是第二个参数标识进制[2-36]

  • 2.1 两个参数都有效 正常转换
  • 2.2 第二个参数 0 undefined null 默认按照10进制转换 但是如果输入的是0x的十六进制优先使用十六进制
  • 2.3 两个参数有一个无效 NaN
Number.parseInt('111', 2) === 7 // true
Number.parseInt('0x11', 0) === 17 // true
Number.parseInt('111', 0) === 111 // true
Number.parseInt('777', 3) // NaN 第一个参数无效
Number.parseInt('777', 99) // NaN 第二个参数无效

parseFloat

尽可能多的将输入解析为一个浮点数,结果有三种 成功 部分成功 NaN

Number.parseFloat('123.456')    // 123.456 成功
Number.parseFloat('123.456abc') // 123.456 部分成功
Number.parseFloat('abc')        // NaN 
Number.parseFloat('1.23e-4')    // 0.000123 成功

toString

Object的toString用于做 类型判断 Number覆盖了这一方法。

  1. 通常用于进制转换
(15).toString(2)   // '1111'
  1. 类型转换->字符串
Number.prototype.toString = () => "重写了";
console.log(`${1}`); // "1" 原始类型直接转换
console.log(`${new Number(1)}`); // "重写了" 引用类型调用toString方法转换

注意与原始类型的自动装箱和拆箱区分开

Number.prototype.test = () => "hello word";
const n1 = new Number('1')
const n2 = 1;
n1 === n2 // false 
n1.test() // hello word
n2.test() // 自动装箱 hello word 

valueOf

引用类型隐式转换会用到 Number类型返回对应的原始值

const numObj = new Number(10);
console.log(typeof numObj); // object

const num = numObj.valueOf();
console.log(num); // 10
console.log(typeof num); // number

Math

这是一个内置对象,提供了与数学相关的函数和属性,如Math.pow、Math.sqrt、Math.abs等。

BigInt(ES2020)

BigInt 是 JavaScript 中的一个内置对象,用于表示任意大小的整数。BigInt 是一种特殊的数字类型,它可以表示大于 2^53 - 1 的整数,而普通数字类型(Number)只能表示这个范围内的整数。

BigInt 可以通过在数字后面添加 n 字符或者通过BigInt函数创建。

let b1 = 1234567890123456789012345678901234567890n;
let b2 = BigInt(1234567890123456789012345678901234567890)
let b3 = BigInt('1234567890123456789012345678901234567890')

b1 === b2 // false
b1 === b3 // true

b2传入的是一个数字 超出了Number的最大值 
在转换为BigInt之前就已经丢失精度了 所以转化后和b1是不相等的

b3传入的是一个字符串 可以不丢失精度的转化为BigInt类型 所以b3和b1相等。

关于BigInt注意点:

  1. BigInt不能new
  2. 转换为Number时 注意精度丢失问题
  3. BigInt和Number是两个类型 不能混合运算
let bigint = 123n; 
let num = 456; 
console.log(bigint + num); // 抛出错误


let bigint = 123n; 
let num = 456; 
console.log(bigint + BigInt(num)); // 输出 579n

let bigint = 123n; 
let num = 456; 
console.log(Number(bigint) + num); // 输出 579

进制&转换

二进制(binary):在数字前面加上0b或0B。

0b111 === 7 // true 二进制7 === 十进制7

八进制(octal):在数字前面加上0o或0O

在ES6之前,JavaScript使用在数字前面加上0的方式来表示八进制数字。例如,010表示八进制数10,其十进制值为8。
但是,这种表示方法在严格模式下是禁止的,因为它可能会引起混淆。
从ES6开始,JavaScript引入了新的表示方法,即在数字前面加上0o或0O。

0o11 === 9 // true 8进制9 === 十进制9

十六进制:在数字前面加上0x或0X

0x1a === 26 // true 十六进制26 === 十进制26

那么问题来了, 二进制和八进制都是对应的英文单词首字母 十六进制单词是hexadecimal为什么十六进制使用x来表示呐?

这个约定的来源可以追溯到C语言。

在C语言中,所有的常量(包括数字)都是以0开头的。为了区分十进制、八进制和十六进制,C语言规定以0开头的是八进制数,以0x或0X开头的是十六进制数。 当JavaScript被设计出来的时候,为了与C语言保持一致,也采用了这个约定。所以在JavaScript中,我们也使用0x或0X来表示十六进制数。

至于为什么选择"x",可能是因为"x"在英语中经常被用来表示"未知数"或"变量",在这里可能被用来表示"这是一个变量的数值,其进制是16"。但这只是一种猜测,实际的原因可能需要询问C语言的设计者。

N进制字符串

Number.parseInt('111', 2) === 7
Number.parseInt('111', 8) === 73
Number.parseInt('111', 16) === 273

进制转换

进制转换只有两种 N进制转十进制 十进制转N进制

十进制转N进制: toString

(15).toString(2)   // '1111'
(15.1).toString(2)
//'1111.0001100110011001100110011001100110011001100110011'
(15).toString(8)   // '17'
(15).toString(16)  // 'f'

N进制转十进制: parseInt

Number.parseInt('11',2)  // 3
Number.parseInt('11',16) // 17
Number.parseInt('11',8)  // 9

一个例子

ip转二进制

function iPto2(ip){
   return ip.split('.').map(item=>{
       return Number.parseInt(item).toString(2).padStart(8, '0')
    }).join('') 
}
iPto2('172.23.10.37') // 10101100000101110000101000100101

参考

  1. mdn_Number
  2. sec-ecmascript-language-types-number-type
  3. javascript-number
  4. ruanyifeng_number
  5. BigInt