js基石之数据类型一:类型分类&存储&区别

94 阅读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

类型分类

8种类型:

记忆(223 + 1):2空(Null,Undefined) 2新(Symbol,BigInt) 3旧(Number,String,Boolean),一个引用object

原始类型七种:

  1. Number:表示数字,包括整数和浮点数。
  2. String:表示文本数据,或字符串。
  3. Boolean:表示逻辑值,包括真(true)和假(false)。
  4. Null:表示空值,或者说没有值。
  5. Undefined:表示未定义,通常用于表示变量已声明但未赋值。
  6. Symbol(es2015):表示唯一的标识符,主要用于对象的属性名。
  7. BigInt(es2020):表示任意精度的整数,可以安全地存储和操作大整数。

原始类型占用多少存储空间呐?

在JavaScript中,基础数据类型的存储空间并没有明确的规定。这是因为JavaScript是一种高级语言,它抽象了许多底层细节,包括内存管理。因此,不同的JavaScript引擎可能会以不同的方式存储这些值。

然而,我们可以大致估计每种基础数据类型的存储空间:

  1. Boolean:一个布尔值通常占用1字节的存储空间。
  2. Number:在JavaScript中,所有的数字都是双精度浮点数,通常占用8字节的存储空间。
  3. String:在JavaScript中,字符串是由16位(2字节)的Unicode字符组成的。因此,一个字符串通常占用字符数 * 2字节的存储空间。
  4. nullundefined:这两种类型的值通常占用1字节的存储空间。
  5. Symbol:Symbol类型的值是唯一的,它们的存储空间取决于实现和符号的描述符的长度。
  6. BigInt: 通常可以用以下公式来估计, 内存占用(字节) = 值的二进制位数 / 8(一个字节8个bit),对于BigInt值123456789012345678901234567890n,它的二进制表示大约有100位(实际上稍微少一些)。这是因为这个数字大约等于2^100。所以,这个数字在内存中的存储空间大约是100/8 ≈12.5字节

请注意,这些都是大致的估计,实际的存储空间可能会因为各种因素(例如内存对齐、垃圾回收等)而有所不同。

引用类型一种Object:除了原始类型都是引用类型

  1. Object:表示一组键值对,是JavaScript中最基本的复杂数据类型。
  2. Array:表示一组有序的值,是Object的一种特殊类型。
  3. Function:表示可执行的代码块,是Object的一种特殊类型。
  4. RegExp:表示正则表达式,是Object的一种特殊类型。
  5. Date:表示日期和时间,是Object的一种特殊类型。 等等还有很多种这里不一一列举。

区别

  1. 存储方式:原始类型的值直接存储在变量中也就是直接在栈里,而对象类型的值则是存储在堆内存中,变量实际上存储的是对这个对象的引用地址。这是最本质的区别截屏2024-01-08 上午11.44.14.png
  2. 可变性:原始类型的值是不可变的,也就是说,一旦一个原始类型的值被创建,就不能改变这个值。而对象类型的值是可变的,可以随时添加、修改或删除其属性。
    例如:
var str = "hello";
str[0] = "H";
console.log(str); // 输出 "hello"

在这个例子中,我们试图改变字符串str的第一个字符,但是输出的结果仍然是原来的字符串。这是因为字符串是原始类型的值,一旦创建就不能改变。

var obj = {x: 1};
obj.x = 2;
console.log(obj); // 输出 {x: 2}

在这个例子中,我们改变了对象obj的x属性的值,输出的结果显示x属性的值已经被成功改变。这是因为对象是可变的,我们可以随时添加、修改或删除其属性。

  1. 比较方式:原始类型的值是通过值来比较的,也就是说,如果两个原始类型的值相等,那么它们就是相等的。而对象类型的值是通过引用来比较的,也就是说,即使两个对象的属性完全相同,它们也不一定相等,除非它们引用的是同一个对象。
let n1 = 123;
let n2 = 123;
let o1 = {n: 1};
let o2 = {n: 1};
console.log(n1 === n2) // true
console.log(o1 === o2) // false
  1. 方法和属性:原始类型的值没有方法和属性(但是js会自动装箱和拆箱)。而对象类型的值可以有自己的方法和属性。
let str = 'hello'
str.substr(2) 
// 自动创建一个匿名字符串对象String 然后使用对象访问对应的方法 使用完成后对象被丢弃。

let num = 12;
12.toString() 
// 报错 数字字面量后面直接跟上`.`操作符会被解析为小数点,而不是属性访问操作符。
// 所以`12.toString()`会导致语法错误,因为JavaScript会尝试解析`12.`为一个数字,
// 然后期望在其后面跟着数字而不是字符串。
(12).toString() // 返回字符串’12‘
  1. 变量传递方式:原始类型在变量传递的过程中是 传递前后两者完全独立无关互不影响。引用类型在变量传递的过程中是将变量的地址拷贝给另一个变量,因为传递前后两个变量指向的是一个地址所以共用一个堆对象,会互相影响。
let a1 = 12;
let a2 = a1;
a2 = 99;
console.log(a1) // 12;
console.log(a2) // 99;
let arr1 = [1,2,3];
let arr2 = arr1;
arr2.push(4);
console.log(arr1); // [1,2,3,4]
console.log(arr2); // [1,2,3,4]

变量传递方式中 ES2015的特例

在es2015之前js的数据互相引用传递的情况只有两种即值传递&引用传递,但是es2015新增了一种模块化的方式import/export,在import/export中无论导出的是一个值还是一个引用对象,本质上导出的都是地址,因此如果一个变量被多个模块导入,然后在改变变量的值,其他所有导入的都是变化后的最新值,这是es2015所谓的实时绑定

a.js
export let a = 123;

export let changeA = ()=>{
 a = 99;
}

b.js
import { a, changeA } from 'a.js';
changeA();

c.js
import { a } from 'a.js';
console.log('a:', a) // 99

参考

  1. javaScript 数据类型和数据结构
  2. 细说 JavaScript 七种数据类型 
  3. 数据类型
  4. 引用类型转换原始类型