值范例、实行环境和渣滓接纳

ECMAscript中的变量是松懈范例的,即它在差别的时代可以有差别范例的值,这也是ECMAscript最壮大的的特征之一.

基础范例和援用范例的值

javascript的值范例有两种:基础范例 援用范例。基础范例的值是指的简朴的数据段,基础范例有五种,依次是:Undefined Boolean String Number Null,而援用范例的值指的是由多个值构成的对象.

基础范例值和援用范例值的区分

保留体式格局差别

基础范例值的变量是保留确切的值.而援用范例值的变量保留的是一个指针,这个指针指向内存中的对象.

援用范例的值可以动态增加属性和要领.

复制情势差别

当基础范例值的变量被复制给另一个变量时,内存中会新拓荒一个存储空间来存储这个新变量的值,新变量的值和被复制的变量的值保留在两个差别的存储空间中,它们互相自力,互不影响.

当援用范例值的变量被复制给另一个变量时,内存中不会拓荒新的空间,新变量保留的也是一个指向内存中对象的指针,新变量和旧变量指向的是同一个存储地区,因而转变个中一个变量的值,另一个变量也会随之转变.


var name = 'yuhualingfeng';
var anotherName = name;
alert(anotherName);  // yuhualingfeng

anoherName = 'Jake';
alert(anotherName); // Jake
alert(name); //yuhualingfeng 

如上所示,转变了anotherName的值并没影响到name变量的值.

var obj = new Object();
obj.name = 'yuhualingfeng';

var anotherObj = obj;

alert(anotherObj.name); // yuhualingfeng

anotherObj.name = 'Jake';

alert(anotherObj.name); // Jake
alert(obj.name);  Jake

转变anotherObj对象的name属性值后,obj对象的name属性值也随之转变,这一点可以推断出两者指向的是同一个存储地区.

实行环境(作用域)

实行环境是Javascript中最为主要的一个观点.实行环境定义了变量或函数有权接见的其他数据,定义了它们各自的行动.每一个实行环境都有一个与之关联的变量对象

全局实行环境是最外层的实行环境,全局实行环境中有一个window全局对象,全局环境中的一切变量都可以经由过程window对象接见.

除全局实行环境外,每一个函数也都有一个本身的实行环境.当实行某个函数时,会发生一个由变量对象构成的作用域链,作用域链的存在是为了让解析器可以有序的找寻标识符,如果在函数中运用某个变量时,起首解析器会在函数本身的变量对象中找寻这个变量的标识符,如果没找到,会继承查找上一个变量对象,直到找到这个标识符为止.查找标识符时,
解析器会从作用域链中函数本身的变量对象最先寻觅,直至全局实行环境中的变量对象,如果在全局环境中的变量对象中没找到标识符,解析器就会抛出毛病.

var age = 30;

function changeAge(){

age = 40;

}

changeAge();

alert(age); // 40

changeAge的作用域链中有两个变量对象,本身的变量对象和全局环境的变量对象,当实行changeAge函数时,调用了age变量,解析器先在changeAge变量对象中查找此变量,没有找到,然后继承查找上一个变量对象全局变量对象,找到了age变量.

有一点要注重的是,javascript中的作用域和其他编程言语差别,它没有块级作用域,看下面的例子:

function test(){

      for(var i = 0,len =10;i < len;i++){
    doSomething(i);
    console.log(i); //  10
    }

}
test();

在for语句中定义的i变量,在for语句外可以被接见到.javascript中定义的变量会把它增加到近来实行环境的变量对象中.这里会把i变量增加到test函数的变量对象中.

渣滓网络

Javascript具有自动渣滓网络机制,实行环境会担任治理代码实行过程当中运用的内存.

渣滓接纳机制的道理:渣滓网络器找出那些不再继承运用的变量,然后开释其占用的内存,渣滓网络器会按牢固的事宜周期性的实行内存接纳.

用于标记无用变量战略因完成而异,详细到浏览器中的插件,一般有以下两种战略:标记清晰 援用计数

标记消灭

标记消灭是浏览器中最经常使用的一种渣滓网络体式格局.当变量进入环境时(例如用var 声明一个变量),就将这个变量标记为进入环境,当变量脱离环境时,就将这个变量标记为脱离环境,固然,做这类标记的体式格局可以有多种,比方可以经由过程翻转某个特别的位来纪录变量适宜进入环境,或许运用一个”进入环境的”变量列表及一个”脱离环境的”变量列表来跟踪哪一个变量发生了变化.

渣滓接纳器会给一切存储在内存中的变量都加上标记(进入环境),当变量在实行环境中没法被接见到时,就会加上另一种标记(脱离环境),待下一次渣滓接纳器举行接纳时将接纳其占用的内存.

援用计数

另一种不太罕见的接纳体式格局是援用计数.援用计数就是计算出变量被援用的次数,当一个变量被赋值为一个援用范例的值时,援用范例值的援用次数就加1,当这个变量指向另一个援用范例的值时,援用范例值的援用次数就减1.当渣滓接纳器举行检测时,发明援用范例的值被援用的次数即是0时就会接纳其占用的空间.
这类渣滓接纳机制会在轮回援用中致使严峻的内存泄漏,看下面例子:

function Test(){
    var obj1 = new Object();
  var obj2 = new Object();
  
  obj1.property = obj2;
  obj2.property = obj1;
}

Test函数实行完成后,经由过程援用计数的机制举行渣滓接纳时,会发明obj1指向的援用范例值的援用计数为1(被obj2.property援用),obj2指向的援用范例值的援用计数为1(被obj1.property援用),因而这两个援用范例的值就不会被接纳,如果屡次实行此函数就会形成严峻的内存泄漏.
为了处理这个题目须要手动开释内存:

obj1.property = null;
obj2.property = null;

IE浏览器中IE9之前的版本的BOM和DOM中的对象采纳的就是援用计数的接纳机制,因而我们在运用时需分外注重.
另有一点须要注重的是:全局环境中的变量只会在应用程序完毕(比方封闭浏览器)时才会脱离实行环境,所以我们须要尽量的手动开释无用的变量占用的内存.

    原文作者:yuhualingfeng
    原文地址: https://segmentfault.com/a/1190000003793005
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞