本文分两个部分讨论变量存储模式
- 局部/ 全局/ 闭包变量的存储机制: 在这部分我们讨论什么样的变量有资格存储在栈中
- 不同类型变量的存储机制: 在这部分我们讨论存储在栈中的元素究竟存的是字面量还是引用
先说结论: 万物都存在堆中, 有的变量会在栈上存储引用地址
堆与栈
- 堆是一个很大的内存存储空间, 你可以在里面存储任何类型数据. 操作系统不会自动回收. 在栈中存储不了的数据比如对象就会被存储在堆中, 在栈中呢是保留了对象在堆中的地址, 也就是对象的引用.
- 栈是内存中一块用于存储局部变量和函数参数的线性结构, 遵循着先进后出的原则. 数据只能顺序的入栈, 顺序的出栈. 内存中栈区的数据, 在函数调用结束后, 就会自动的出栈, 不需要程序进行操作, 操作系统会自动回收
于是出现了一个问题, 在闭包出现时, 函数是如何访问到闭包所在的已经销毁的栈中的变量的呢?
局部/全局/闭包变量的存储机制
-
局部变量: 最简单的, 局部变量存储在作用域所在的栈空间中, 例如
function demo() { let a = 1; let b = '213'; let c = [213]; let d = new Object(); } console.dir(demo); // ƒ demo() // arguments: null // caller: null // length: 0 // name: "demo" // prototype: // constructor: ƒ demo() // [[Prototype]]: Object // [[FunctionLocation]]: demo.html:53 // [[Prototype]]: ƒ () // [[Scopes]]: Scopes[1] // 0: Global {0: Window, window: Window, self: Window, document: document,在上面我们找不到定义的变量, 在DevTools的内存-堆分析中也找不到他们
-
全局变量
-
使用
var声明的全局变量
使用var声明全局变量其实仅仅是为global对象添加了一条属性, 全局变量会被默认添加到函数作用域链的最底端, 也就是[[Scopes]]中的最后一个var aaa = 1; // 随便var一个变量 // 等同于 window.aaa = 1; console.dir(()=>{ }) // 随便打印一个函数看看他的作用域 // anonymous() // length: 0 // name: "" // arguments: (…) // caller: (…) // [[FunctionLocation]]: VM167:1 // [[Prototype]]: ƒ () // [[Scopes]]: Scopes[1] <- 看到函数的作用域 // 0: Global <- 只有global(window)作用域 // aaa: 1 <- 看到window上的aaa // alert: ƒ alert() // atob: ƒ atob() // blur: ƒ blur() // btoa: ƒ btoa() -
使用
let/const声明全局变量不会修改window对象, 而是将变量的声明放在了一个特殊的对象Script下let t1 = 1; const t2 = 2; console.dir(()=>{ }) // anonymous() // length: 0 // name: "" // arguments: (…) // caller: (…) // [[FunctionLocation]]: VM99:1 // [[Prototype]]: ƒ () // [[Scopes]]: Scopes[2] <- 查看作用域 // 0: Script {t1: 1, t2: 2} <- 看到这些数据被存储到了Script对象中 // 1: Global {window: Window, self: Window, document: document,...}
-
-
闭包中的变量: 闭包中的变量会在子函数调用的时候存储为一个对象(存储在堆中), 并在
[[Scopes]]的Closure(闭包)中体现function testCatch1 () { let a1
本文探讨JavaScript中变量的存储机制,包括堆与栈的区别、局部/全局/闭包变量的存储,以及不同类型变量(如String、Number、OddBall等)如何存储。结论指出,所有变量都在堆中,栈中存储引用地址,基础类型中小整数存储在栈中,其余在堆中。
最低0.47元/天 解锁文章

731

被折叠的 条评论
为什么被折叠?



