变量不是声明完就完事了
写代码的时候,很多人觉得只要把变量声明出来,后面用就是了。可实际上,变量从诞生到消失,中间经历的过程远比想象中复杂。尤其是在函数嵌套、循环频繁的场景下,一个没管好的变量可能让程序莫名其妙地出错,比如值被意外覆盖,或者内存占用越来越高。
举个生活中的例子:你去超市买东西,拿了个购物篮,放进几样商品。如果结账后你忘了还篮子,下次再去又拿新篮子,久而久之超市的篮子就被占用了。程序里的变量也一样,用完了不及时释放,系统资源就会被一点点吃掉。
变量的“出生”和“死亡”
在大多数编程语言里,变量的生命周期从它被声明那一刻开始。比如在 JavaScript 中:
function calculate() {
let result = 0;
for (let i = 1; i <= 5; i++) {
result += i;
}
return result;
}这里的 result 和 i 都是在函数执行时创建的,属于局部变量。一旦函数执行结束,它们的使命也就完成了,会被自动清理。这个过程就是生命周期的终结。
作用域决定“能活多久”
变量能不能被访问,取决于它所在的作用域。全局变量从脚本加载就开始存在,直到页面关闭才消失。而局部变量只在函数或代码块内有效。
比如下面这段代码:
let globalName = '张三';
function greet() {
let localName = '李四';
console.log(globalName); // 能访问
console.log(localName); // 能访问
}
greet();
console.log(globalName); // 还能访问
console.log(localName); // 报错!localName 已经“死”了可以看到,localName 只能在 greet 函数里用,函数一结束,它就无法再被触及。这就是作用域对生命周期的限制。
闭包:让变量“多活一会儿”
有时候我们希望变量在函数执行完后还能保留,这时候闭包就派上用场了。闭包的本质是函数记住了它外部的变量环境。
function createCounter() {
let count = 0;
return function() {
count++;
return count;
}
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2虽然 createCounter 执行完了,但里面的 count 并没有被回收,因为它被内部函数引用着。这种“延长寿命”的方式很实用,但也容易造成内存泄漏,如果不用了还不手动断开引用,系统负担就会加重。
垃圾回收不是万能的
现代语言大多有自动垃圾回收机制,会定期清理没人用的变量。但这不意味着你可以完全放手不管。比如给全局变量赋了一个大数组,之后再也不用了却没清空,那它会一直占着内存。
解决办法很简单:不需要时主动释放。
let bigData = [/* 假设这里有一万个元素 */];
// 使用完之后
bigData = null; // 主动通知系统可以回收就像用完购物篮主动还回去,方便别人接着用。主动管理变量生命周期,程序才能跑得更轻快。