JavaScript 数据存储大揭秘:从栈到堆的奇妙之旅 🚀

113 阅读4分钟

JavaScript 数据存储大揭秘:从栈到堆的奇妙之旅 🚀

作为一个在代码世界里摸爬滚打的程序员,你是否曾经被 JavaScript 的数据存储搞得晕头转向?别担心,今天我们就来一场说走就走的内存之旅!

开场白:JavaScript 是个什么样的语言?🤔

首先,让我们来认识一下我们的主角 —— JavaScript。

JavaScript 是动态语言,弱类型语言

  • 动态语言:就像变色龙一样,不需要提前声明类型,运行时自动确定
  • 弱类型语言:就像万能胶水,不同类型之间可以进行隐式转换

这就是为什么你可以写出 "5" + 3 = "53" 这种让人又爱又恨的代码 😅

数据类型家族大聚会 👨‍👩‍👧‍👦

原始类型(基本类型)- 简单朴素的一家人

// 基本数据类型的全家福
let str = 'hello'        // String - 话痨
let num = 12345          // Number - 数学家
let bool = true          // Boolean - 二选一困难户
let un = undefined       // Undefined - 迷茫青年
let nul = null          // Null - 空虚寂寞冷
let sym = Symbol('hello') // Symbol - 独一无二的存在
// BigInt - 处理超大整数的大力士

引用类型 - 复杂多变的一家人

// 引用类型就像是豪华套房
let obj = {}      // Object - 万能收纳盒
let arr = []      // Array - 有序排队的好学生
let func = function(){} // Function - 干活的工具人
let date = new Date()   // Date - 时间管理大师

字面量 vs 构造函数:两种不同的"出生方式" 🏥

看看这个有趣的对比:

// 字面量方式 - 简单直接
let str = 'hello';
console.log(str); // 'hello'

// 构造函数方式 - 包装豪华
let str1 = new String('hello');
console.log(str1); // String { 'hello' }

就像买手机,一个是裸机,一个是豪华礼盒装,功能一样,包装不同!

内存空间:V8 引擎的三室一厅 🏠

当 V8 引擎执行 JavaScript 代码时,它会开辟一个"三室一厅":

  • 代码空间:存储代码(就像书房)
  • 栈内存:存储基本类型的值(就像卧室,简单整洁)
  • 堆内存:存储引用类型的值(就像客厅,复杂多样)

栈内存 vs 堆内存:一场存储的较量 ⚔️

基本类型:栈内存的乖宝宝

function foo(){
    var a = 'zz'
    var b = a    // 复制值,各自独立
    var c = {name:'zs'}
    var d = c    // 复制地址,共享对象
}

基本类型就像是复印机,每次赋值都是复制一份全新的副本:

// 基本类型的独立性
var a = 1
var b = a
a = 2
console.log(a); // 2
console.log(b); // 1 - b 不受影响

引用类型:堆内存的共享主义者

// 引用类型的共享特性
function foo(){
    var a = {name:'zs'}
    var b = a           // 共享同一个对象
    a.name = 'zz'       // 修改对象属性
    console.log(a);     // {name: 'zz'}
    console.log(b);     // {name: 'zz'} - 一起变化!
}

引用类型就像是房屋租赁,多个变量可以拿到同一套房子的钥匙!

实战案例:对象的"整容手术" 💄

让我们看一个有趣的例子:

// 创建一个"人物"对象
let obj = {
    name: 'zs',
    age: 18,
    sex: 'male',
    health: 100,
    smoke: function(){
        console.log('来根华子');
        this.health -= 10;
    },
    drink: function(){
        console.log('来瓶台子');
        this.health += 10;
    }
}

// 动态添加属性 - 就像给对象"整容"
let zsGirl = 'myGirl';
obj[zsGirl] = 'ls';  // 添加女朋友属性
console.log(obj[zsGirl]); // 'ls'

函数参数传递:一场"移花接木"的好戏 🎭

function foo(person){
    person.age = 18;    // 修改原对象
    person = {          // 重新赋值,指向新对象
        name: 'zz',
    }
    return person;
}

let p1 = {
    name: 'zs',
    age: 20,
}
let p2 = foo(p1);
console.log(p1); // {name: 'zs', age: 18} - 年龄被改了
console.log(p2); // {name: 'zz'} - 全新的对象

这就像是:

  1. 你把房子钥匙给朋友
  2. 朋友进去重新装修了(修改属性)
  3. 然后朋友又买了套新房子(重新赋值)
  4. 你的房子被装修了,但朋友住的是新房子!

总结:内存管理的智慧 🧠

理解 JavaScript 的数据存储机制,就像理解人际关系:

  • 基本类型:独立自主,互不干扰
  • 引用类型:共享资源,牵一发而动全身

掌握了这些,你就能避免很多莫名其妙的 bug,写出更优雅的代码!

记住:栈内存存值,堆内存存址,引用类型要小心! 💡


希望这篇文章能帮你理清 JavaScript 数据存储的来龙去脉。如果觉得有用,别忘了点赞收藏哦!有问题欢迎在评论区讨论~ 🎉