JavaScript数据存储:变量们的"豪宅"与"胶囊公寓"

62 阅读4分钟

你有没有想过,为什么let a = 1let b = {name: 'Tom'}在赋值后表现不同?为什么修改a不影响b,但修改对象属性却会?今天,我们就来扒一扒JavaScript中变量们的"居住条件"——数据存储机制。

一、数据类型:变量的"身份标签"

JavaScript里的变量分两大派系:

1. 原始类型(基本类型):"单身贵族"们

这些是JavaScript里的"基本居民",共有7位:

  • string:字符串,比如'hello'
  • number:数字,包括整数和小数
  • boolean:布尔值,只有true和false
  • null:空值(虽然typeof返回'object',但它真的是原始类型)
  • undefined:未定义
  • symbol:唯一值,即使描述相同也不等
  • bigint:大整数,专门处理超出安全范围的数字

原始类型就像"单身贵族",性格独立,赋值时是值传递——复制一份全新的自己。就像你复制了一篇文章,修改副本不会影响原文。

let a = 1;
let b = a;
a = 2;
console.log(a); // 2
console.log(b); // 1,不受a的影响

2. 引用类型(复杂类型):"拖家带口"的大户

这些是JavaScript里的"大家庭",主要有:

  • Object:对象
  • Array:数组
  • function:函数
  • Date:日期对象

引用类型就像"拖家带口"的大户,赋值时是引用传递——传递的是地址(引用)。就像两个人共用一个快递柜的钥匙,你放东西进去,另一个人也能看到。

let obj1 = {name: '张三'};
let obj2 = obj1;
obj1.name = '李四';
console.log(obj2.name); // '李四',跟着变了

二、JavaScript:一门"随性"的语言

JavaScript是动态弱类型语言,这是什么意思?

  • 动态类型:变量不需要提前声明类型,赋值时才确定。就像你点奶茶,想喝什么临时决定,不需要提前预约。
  • 弱类型:支持隐式类型转换。就像你说"我要奶茶",店员可能会默认给你加珍珠,自动给你转换了。
let a = '123';
a = 456; // 没问题,变量类型说变就变
let b = '1' + 2; // '12',字符串拼接
let c = '1' * 2; // 2,自动转成数字计算

三、内存空间:变量们的"住所"

V8引擎在执行JS代码时,会开辟三种内存空间,就像不同档次的住所:

1. 代码空间:"公共图书馆"

存放代码本身的文本,就像图书馆里的书籍,供CPU读取和执行。

2. 栈空间:"胶囊公寓"

存放原始类型数据和引用类型的地址,特点是容量小、访问快。就像市中心的胶囊公寓,虽然小但位置好,适合单身贵族(原始类型)和快递柜钥匙(引用地址)。

3. 堆空间:"豪华别墅"

存放引用类型的具体内容,特点是容量大、结构复杂。就像郊外的豪华别墅,空间大,可以住下整个大家庭(对象的所有属性和方法)。

四、实战演示:变量们的"搬家"过程

来看个经典例子,理解内存中的变量行为:

function foo(person) {
  person.age = 20; // 修改传入对象的属性
  person = {name: '刘洋'}; // 重新赋值
  return person;
}
let p1 = {name: '张三', age: 18};
let p2 = foo(p1);
console.log(p1); // {name: '张三', age: 20}
console.log(p2); // {name: '刘洋'}

这里的关键是:

  1. person参数一开始指向p1的地址(同一个别墅),所以修改person.age会影响p1
  2. 但当person = {name: '刘洋'}时,person就换了一个新地址(搬去了另一个别墅),和p1没关系了
  3. 所以p2拿到的是新别墅的地址,而p1还在原来的别墅里,只是年龄被改了

五、Symbol:数据界的"身份证"

Symbol是个特别的原始类型,它的特点是唯一性——即使描述相同,也是不同的值。就像身份证号,哪怕两个人同名同姓,身份证号也不一样。

let s1 = Symbol('hello');
let s2 = Symbol('hello');
console.log(s1 === s2); // false,虽然描述相同,但不是同一个值

这在需要唯一标识符的场景特别有用,比如对象的唯一属性名。

总结:理解数据存储,写出更稳健的代码

  1. 原始类型是值传递,赋值后互不影响
  2. 引用类型是引用传递,赋值后共享同一个内存地址
  3. JavaScript的动态弱类型特性让它很灵活,但也容易出错
  4. 栈空间存原始类型和引用地址,堆空间存引用类型的具体内容

理解这些概念,能帮你更好地解释代码中的一些"奇怪"现象,写出更稳健、更高效的JavaScript代码。下次遇到变量赋值问题,记得想想变量们的"居住条件"哦!