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变量的生命周期的主要内容,如果未能解决你的问题,请参考以下文章

在不存在的片段上调用片段生命周期和 onCreate 的问题

Android片段生命周期:onResume调用了两次

导航上的片段生命周期重叠

Android 片段生命周期

js变量的生命周期

JS学习之生命周期与垃圾回收机制