js变量的生命周期
Posted Wament
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了js变量的生命周期相关的知识,希望对你有一定的参考价值。
变量的生命周期
1.声明
全局变量:全局声明的变量
局部变量:函数内声明的变量,函数参数
声明局部变量的时候必须用var,否则产生的是全局变量
1 scope = "global"; 2 function checkscope2() { 3 scope = "local"; 4 myscope = "local"; 5 } 6 checkscope2(); 7 console.log(scope);//输出local,全局变量被修改 8 console.log(myscope);//输出local,全局命名空间被搞乱了
使用var声明的变量是不可配置的,即无法通过delete运算符删除
1 var truevar = 1;//不可配置的全局变量 2 fakevar = 2; 3 this.fakevar2 = 2; 4 delete truevar;//出错 5 delete fakevar;//执行成功 6 delete this.fakevar2;//执行成功
在函数内部中局部变量会遮盖同名的全局变量
1 var scope = “global”;//声明一个全局变量 2 function checkscope(){ 3 var scope = “local”;//声明一个同名的局部变量 4 console.log(scope);//输出”local” 5 }
2.变量提升(变量声明提前)
即函数中声明的所有变量都被“提前”至函数体的顶部,这步操作是在代码开始运行之前的javascript引擎预编译时执行的。
例:
1 var scope = “global”; 2 function f(){ 3 console.log(scope);//输出”undefined”,而不是”global” 4 var scope = “local”;//变量在这里声明且赋初值,但变量本身在函数体内任何地方均是有定义的 5 console.log(scope);//输出”local” 6 }
实际上,上述的代码等价于:
1 var scope = “global”; 2 function f(){ 3 var scope 4 console.log(scope);//输出”undefined”,而不是”global” 5 scope = “local”;//变量在这里声明且赋初值,但变量本身在函数体内任何地方均是有定义的 6 console.log(scope);//输出”local” 7 }
3.全局变量与局部变量的作用域
全局变量:当声明一个全局变量时,实际上是定义了全局对象window的一个属性,在任何地方都可以对其进行访问
局部变量:局部变量在声明它的函数体内以及其所嵌套的函数体内是有定义的。
作用域链:
1 var color = "blue"; 2 function changeColor(){ 3 var anotherColor = "red"; 4 function swapColors(){ 5 var tempColor = anotherColor; 6 anotherColor = color; 7 color = tempColor; 8 // 这里可以访问 color、anotherColor和tempColor 9 } 10 //这里可以访问color和anotherColor,但不能访问tempColor 11 swapColors(); 12 } 13 // 这里只能访问 color changeColor();
矩形表示特定的执行环境
其中,内部环境可以通过作用域链访问所有的外部环境,但 外部环境不能访问内部环境中的任何变量和函数。。每个环境都 可以向上搜索作用域链,以查询变量和函数名;但任何环境都不能通过向下搜索作用域链而进入另一个执行环境。
对于上面的例子而言,其作用域链中包含 3个对象:swapColors()的变 量对象、changeColor()的变量对象和全局变量对象。swapColors()的局部环境开始时会先在自己的 变量对象中搜索变量和函数名,如果搜索不到则再搜索上一级作用域链,即changeColor()的作用域链
作用域链的延长 :
1 var outer = { 2 value : "outer", 3 index : 0 4 } 5 function test() { 6 var inner = "inner"; 7 with(outer){//将outer对象添加到此作用域,可以在其中直接使用其方法和属性 8 value = inner; 9 } 10 } 11 test(); 12 console.log(outer.value);//输出"outer"
除了with,我们还可以使用catch延长作用域链
5.垃圾回收
标记清除(常用):
工作原理:是当变量进入环境时,将这个变量标记为“进入环境”。当变量离开环境时,则将其标记为“离开环境”。标记“离开环境”的就回收内存。
工作流程:
1.垃圾回收器,在运行的时候会给存储在内存中的所有变量都加上标记。
2.去掉环境中的变量以及被环境中的变量引用的变量的标记。
3.再被加上标记的会被视为准备删除的变量。
4.垃圾回收器完成内存清除工作,销毁那些带标记的值并回收他们所占用的内存空间。
引用计数:
工作原理:跟踪记录每个值被引用的次数。
工作流程:
1.声明了一个变量并将一个引用类型的值赋值给这个变量,这个引用类型值的引用次数就是1。
2.同一个值又被赋值给另一个变量,这个引用类型值的引用次数加1.
3.当包含这个引用类型值的变量又被赋值成另一个值了,那么这个引用类型值的引用次数减1.
4.当引用次数变成0时,说明没办法访问这个值了。
5.当垃圾收集器下一次运行时,它就会释放引用次数是0的值所占的内存。
弊端:在循环循环引用中变量的引用次数不会为零则变量不会被回收
1 function test(){ 2 var a={}; 3 var b={}; 4 a.prop=b;//a的引用次数为2 5 b.prop=a;//b的引用次数为2 6 }
而为了解决这种问题,可以显性地切断引用,即将变量的值设为null
现在大部分的浏览器都是采用标记清除的垃圾回收机制,而IE的BOM和DOM中的对象是以引用计数方式进行垃圾回收的COM对象的形式存在的,所以会有导致变量不能被回收的现象。但是在IE9之后就取消了COM对象的形式。
#本文有写的不好或不对的地方还请各位指出,一起学习!#
以上是关于js变量的生命周期的主要内容,如果未能解决你的问题,请参考以下文章