资讯专栏INFORMATION COLUMN

理解前端数据类型

wums / 2486人阅读

摘要:基本数据类型的值保存在栈内存中的简单数据段,按值访问。文字常量区存储常量字符串保存在栈中保存在栈中,保存在常量区程序代码区存储程序的二进制代码关于数字类型根据关于的描述可知,的数字类型只有一种,使用标准中的双精度浮点数来存储,长度为位。

数据类型

基本数据类型:String,Boolean,Number,undefined,null,Symbol(ES6)
引用数据类型:Object,Functoin,Array,RegExp 等

堆(heap)和栈(stack)
堆和栈都是存放临时数据的内存空间(注意与数据结构堆、栈的区分):
栈时向低地址扩展的数据结构,是一块连续的内存的区域(最大容量是系统预设好的),由编译器自动分配和释放,速度快,用于存放函数的参数值与局部变量的值,只要栈的剩余空间大于申请空间就分配,否则报错异常,其操作方式类似于数据结构中的栈,是先进后出的。

基本数据类型的值保存在栈内存中的简单数据段,按值访问。

堆是在程序运行时(而不是在程序编译时)申请的内存空间,即动态分配内存对其访问(大小受到虚拟内存影响),一般由程序员分配和释放,若没有手动释放则在程序结束时由 OS 回收,操作方式与数据结构中的堆是两回事,类似于链表。

引用数据类型的值是指保存在堆内存中的对象,由于对象的大小不固定不能保存在栈内存中,然而内存地址的大小是固定的,故可以将其保存在栈内存中,也就是说:变量在栈内存中保存的数据实际上是指向堆内存中保存的对象的指针。

对于堆,操作系统有一个记录空闲内存地址的链表,当系统收到申请时,会遍历该链表寻找第一个空间大于所申请空间的堆节点,然后将该节点从空闲区链表中删除,将该节点的空间分配给程序,若是找到的节点地址空间大于申请的大小,系统会把剩余的节点空间重新添加到内存空闲区链表中。
(故而使用堆时内存地址不连续,且容易产生碎片)

内存中的其他空间:
全局区(静态区):存储全局变量和静态变量,程序结束后由系统释放。

文字常量区:存储常量字符串

char *p1; // p1 保存在栈中
char *p2 = "test"; // p2 保存在栈中,test 保存在常量区
程序代码区:存储程序的二进制代码
关于 Number 数字类型
In JavaScript, Number is a numeric data type in the double-precision 64-bit floating point format (IEEE 754). In other programming languages different numeric types can exist, for examples: Integers, Floats, Doubles, or Bignums.

根据 MDN 关于 Number 的描述 可知,javascript 的数字类型只有 number 一种,使用 IEEE754 标准中的双精度浮点数来存储,长度为64位。

符号位 指数位 小数位
0 00000000000 00000...0000000000000000000000000
1 bit 11 bit 52 bit
问题:根据 IEEE754 计算 0.1 + 0.2 = ? 使用乘二取整法计算 0.1 的二进制表示形式

0.1 =
(0.00011)2 0011 无限循环 =
(-1)^0 2^(-4) (1.1001)2 1001 无限循环

0.2 =
(-1)^0 2^(-3) (1.1001)2 1001 无限循环

由于小数位仅储存 52 bit, 储存时会将超出精度部分进行 "零舍一入"
值类型 小数位存储范围内 存储范围外
无限精确值 1001 1001 1001 1001 ... 1001 1001 1001 1001 1001...
实际存储值 1001 1001 1001 1001 ... 1001 1001 1010 -

故而 0.1 和 0.2 的浮点数存储形式表示为:

浮点数值 符号位 指数值 小数位
0.1 0 -4 1001 1001 1001 1001 ... 1001 1001 1010
0.2 0 -3 1001 1001 1001 1001 ... 1001 1001 1010
0.1 + 0.2
在计算浮点数相加时需要先进行“对位”,将较小的指数化为较大的指数,并将小数部分相应右移。

0.1 =
(−1)^0 2^(−3) (0.11001100110011001100110011001100110011001100110011010)2

0.2 =
(−1)^0 2^(−3) (1.1001100110011001100110011001100110011001100110011010)2

0.1 + 0.2 =
(−1)^0 2^(−2) (1.0011001100110011001100110011001100110011001100110100)2 =
0.30000000000000004

解决方案

mathjs (https://github.com/josdejong/...

decimal.js (https://github.com/MikeMcl/de...

big.js (https://github.com/10081677wc...

排除直接使用超大数或者超小数的情况,出现这种问题基本是浮点数的小数部分在转成二进制时丢失精度造成的,所以我们可以将小数部分转换成整数后再计算,需要注意的是乘法操作也是一种浮点数计算,在转换过程中可能存在精度问题。

所以不要直接通过计算将小数转换成整数!我们可以通过字符串操作:移动小数点的位置来转换成整数,最后再同样通过字符串操作转换回小数。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/83224.html

相关文章

  • 前端基础进阶(一):内存空间详细图解

    摘要:一栈数据结构与不同,中并没有严格意义上区分栈内存与堆内存。引用数据类型的值是保存在堆内存中的对象。不允许直接访问堆内存中的位置,因此我们不能直接操作对象的堆内存空间。为了更好的搞懂变量对象与堆内存,我们可以结合以下例子与图解进行理解。 showImg(https://segmentfault.com/img/remote/1460000009784102?w=1240&h=683); ...

    _Suqin 评论0 收藏0
  • 一名【合格】前端工程师的自检清单

    摘要:在他的重学前端课程中提到到现在为止,前端工程师已经成为研发体系中的重要岗位之一。大部分前端工程师的知识,其实都是来自于实践和工作中零散的学习。一基础前端工程师吃饭的家伙,深度广度一样都不能差。 开篇 前端开发是一个非常特殊的行业,它的历史实际上不是很长,但是知识之繁杂,技术迭代速度之快是其他技术所不能比拟的。 winter在他的《重学前端》课程中提到: 到现在为止,前端工程师已经成为研...

    罗志环 评论0 收藏0
  • 一名【合格】前端工程师的自检清单

    摘要:在他的重学前端课程中提到到现在为止,前端工程师已经成为研发体系中的重要岗位之一。大部分前端工程师的知识,其实都是来自于实践和工作中零散的学习。一基础前端工程师吃饭的家伙,深度广度一样都不能差。开篇 前端开发是一个非常特殊的行业,它的历史实际上不是很长,但是知识之繁杂,技术迭代速度之快是其他技术所不能比拟的。 winter在他的《重学前端》课程中提到: 到现在为止,前端工程师已经成为研发体系...

    isaced 评论0 收藏0
  • 基础数据结构及js数据存储

    摘要:引用数据类型及堆内存引用数据类型是保存在堆内存中的对象,他的大小是不固定的。基础数据类型在变量对象里可以直接对应对应的值,而引用数据类型是存储在堆里的,在变量对象中对应的是堆内存的地址。因为我们修改本质上是修改了堆内存里的数据。         因为以前前端开发跟数据存储打交道比较少,javascript又具有自动垃圾回收机制。数据结构以及存储相关的概念,其实是很容易被前端er忽略的。...

    Brenner 评论0 收藏0
  • JavaScript系列(四) - 收藏集 - 掘金

    摘要:函数式编程前端掘金引言面向对象编程一直以来都是中的主导范式。函数式编程是一种强调减少对程序外部状态产生改变的方式。 JavaScript 函数式编程 - 前端 - 掘金引言 面向对象编程一直以来都是JavaScript中的主导范式。JavaScript作为一门多范式编程语言,然而,近几年,函数式编程越来越多得受到开发者的青睐。函数式编程是一种强调减少对程序外部状态产生改变的方式。因此,...

    cfanr 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<