js变量、作用域和内存问题的复习**

来源:互联网 发布:网络写文章赚钱的方法 编辑:程序博客网 时间:2024/06/05 11:55

基本类型和引用类型

基本类型指的是简单的数据段,引用类型指那些可能由多个值构成的对象。引用类型的值是保存在内存中的对象。在实际操作中,实际上是在操作对象的引用而不是实际的对象,因此引用类型的值是按引用访问的


js变量的访问有按值和按引用两种,而参数的传递是按值传递的

s所有函数的参数都是按值传递的,也就是把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。基本类型值的传递如同基本类型变量的复制一样,而访问类型值的传递则如同应用类型变量的复制一样。即:在向参数传递基本类型的值时,被传递的值会被复制给一个局部变量(命名参数,或者说arguments对象中的一个元素);向函数传递引用类型的变量时,会把这个值在内存中的地址复制给一个局部变量,因此这个局部变量的变化可以反映在函数的外部

检测类型

typeof是确定一个变量时字符串、数值、布尔值,还是undefined的最佳工具。但是在检测引用类型的值时需要instanceof操作符

执行环境及作用域(执行环境规范了访问权机制,作用域链规范了访问顺序机制)

执行环境是js中最为重要的一个概念。执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。

执行环境的类型只有两种,全局和局部(函数)

每个执行环境都有一个与之关联的变量对象,执行环境中定义的所有变量和函数都保存在这个对象中。虽然我们编写的代码无法访问这个对象,但是解析器在处理数据时会在后台使用它。

全局执行环境是最外围的一个执行环境。根据ES实现的宿主环境不同,表示执行环境的对象也不同,在Web浏览器中,全局执行环境被认为是window对象,因此,所有全局变量和函数都是作为window对象的属性和方法创建的。某个执行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁。全局执行环境直到应用程序退出,如关闭网页或浏览器时才会被销毁


每个function都有自己的执行环境,当执行环境进入一个函数时,函数的环境就会被推入一个环境栈中,而在函数执行结束后,栈将其环境弹出,把控制权返回给当前的环境。ES中的执行流由这样的机制控制着

作用域链

当代码在一个执行环境中执行时会创建变量对象的一个作用域链,作用域链的用途:保证对执行环境有权访问的所有变量和函数可以有序访问。

  1. 作用域链的前端始终都是当前执行环境的代码所在环境的变量对象。(若这个环境是function,则其活动对象作为变量对象,活动对象在最开始时值包含一个变量,即arguments对象)
  2. 作用域链中的下一个变量对象来自包含(外部)环境,再下一个执行环境来自下一个包含环境。
  3. 全局执行环境的变量对象始终都是作用域链的最后一个对象

    var color = "blue";function changeColor(){var anotherColor = "red";function swapColors(){    var tempColor = anotherColor;    anotherColor = color;    color = tempColor;    // 这里可以访问color,anotherColor,tempColor}// 这里可以访问anotherColor,color,不能访问tempColorswapColors();}// 这里只能访问colorchangeColor();

    解释:标识符解析是沿着作用域链一级一级第搜索标识符的过程。而且,搜索过程始终从作用域链的前端开始,然后逐级第向后回溯,知道找到标识符为止
    这里写图片描述
    内部环境可以通过作用域链访问所有的外部环境,但外部环境不能访问内部环境中的任何变量和函数。这些环境之间的联系是线性的,有次序的。每个函数都可以向上搜索作用域链,来查询变量和函数名,但任何环境都不能向下搜索作用域链来进入另一个执行环境

    延长作用域链

    有些语句可以在作用域链的前端临时增加一个变量对象,该变量对象在代码执行后被移除,从而实现作用域链的加长。
    这样的语句有:

    1.try-catch语句的catch块
    2.with语句

function buildUrl(){    var query = "?debug=true";    with(location){        var url = href + query;        // 在with语句中引用href实际应用的是location.href,        //可以在当前执行环境中找到    }    //with内部定义的url变量成了函数执行环境的一部分,所以可以在    //最后作为函数的返回值    return url;}

js没有块级作用域

if (true) {    var color = "blue";}console.log(color);// "blue"

在使用for循环时一定要牢记这一差异:

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

声明变量

使用var声明的变量会自动被添加到最接近的环境中


  1. 在函数内部,最接近的环境是函数的局部环境
  2. 在with语句中,最接近的环境是函数环境
  3. 若初始化变量时没有使用var声明,该变量会自动被添加到全局环境

注意:在编写js代码时,不声明而直接初始化变量是一个常见的错误做法,所以初始化变量之前一定要先声明。在严格模式下,初始化未经声明的变量会导致错误

变量查询

通过搜索来确定变标识符实际代表什么。搜索的过程从作用域链的前端开始,向上逐级产讯与给定名字匹配的标识符。如果在局部环境中找到了变量标识符,搜索过程停止,变量就绪。如果在局部环境中没有找到该变量名,则继续沿着作用域链继续向上搜索。一直追溯到全局环境的变量对象


注意:变量查询时有代价的,访问局部变量要比访问全局变量更快,不用向上搜索作用域链。 JS引擎在优化标识符查询方面做得不错,因此这个差别在将来恐怕也可以忽略不计了


js垃圾收集

JS具有自动垃圾收集机制,执行环境会负责管理代码执行过程中使用的内存,在编写js代码时开发人员不用关心内存使用情况,所需的内存分配以及无用内存的回收都完全实现了自动管理。

垃圾收集机制的原理大概是:找出那些不再继续使用的变量,然后释放其占用的内存。为此,垃圾收集器会按照国定的时间间隔(或代码执行中预定的收集时间),周期性地执行这一操作


局部变量正常的声明周期

局部变量只在函数执行的过程中存在,这个过程中,回味局部变量在栈(或堆)内存上分配相应的空间,以便存储它们的值,然后在函数中使用这些变量,直到函数执行结束。此时,局部变量没有存在的必要了,因此可以释放它们的内存,这种情况下,很容易判断变量是否还有存在的必要。但是并非所有情况都这么容易得出结论。垃圾收集器必须跟踪哪个变量没用,对于不再有用的变量打上标记,以备将来回收期占用的内存

标识无用变量的策略有两种:标记清除和引用计数

常用的垃圾收集方式是标记清除,IE,Firefox,Opera,Safari,Chrome的JS实现使用的都市标记清除式的垃圾收集策略或类似的策略,只不过是垃圾收集的时间间隔互有不同。引用计数垃圾收集存在循环引用的问题,一般都慎用

循环引用的问题,使用null手工中断变量与引用值的连接

循环引用 就是对象A中包含一个指向对象B的指针,而对象B中也包含一个指向A的指针。

IE的JavaScript引擎是使用标记清除策略来实现的,但是其BOM和DOM中的对象就是C++以COM(组件对象模型)对象的形式实现的,COM对象的垃圾收集机制采用引用计数类型实现。因此,只要在IE中涉及COM对象,就会存在循环引用的问题
××××
为了避免循环引用的问题,最好是在不使用对象的时候手工断开原生js对象与DOM元素之间的连接。

obj = null;

将变量设置为null,意味着切断变量与它此前引用的值之间的连接。当垃圾收集器下次运行时,就会删除这些值回收它们的内存

这个问题在IE9得到了解决,IE9把DOM和BOM对象都换成了真正的JavaScript对象。这样就避免了两种垃圾收集算法并存导致的问题,也消除了常见内存泄漏现象

性能问题

确定垃圾收集器的时间间隔是一个非常重要的问题。
IE的垃圾收集器是根据内存分配量运行的,即有几个方面的临界值,一旦超出其中一个,垃圾收集器就会运行。临界值一开始是静态分配的,这就存在着问题,如果一个脚本中包含着很多变量,那么该脚本很可能在其生命周期中一直保有那么多的变量。这样一来垃圾收集其就会频繁地运行,引发严重的性能问题

IE7的引擎优化工作方式是:临界值被调整为可动态修正。极大第提高了IE在运行包含大量js代码的页面时的性能。

有的浏览器中可以触发垃圾收集古城,但是尽量不要使用。IE中,调用window.CollectGarhage().OPera7及更高版本中调用window.opera.collect()也会启动来及收集例程

管理内存(js中需要考虑,浏览器可用内存<桌面应用程序)

使用类似于Java这样的语言编写程序,一般不必操心内存管理的问题。但是js面临的问题不同于一般,最主要的一个问题就是:分配给Web浏览器的可用内存数量通常要比分配给桌面应用程序的少。(为了防止运行js的网页耗尽全部系统内存而导致系统崩溃)。内存限制不仅影响给变量分配内存,同时也影响调用栈以及在一个线程中能够同时执行的语句数量,因此确保占用最少的内存可以让页面获得更好的性能。


优化内存最佳方式:null,解除引用

优化内存占用的最佳方式是解除引用,就是为执行的代码只保存必要的数据,一旦数据不再有用,最好通过将其设置为null来释放其引用

注意:
解除一个值的引用并不意味着自动回收该值所占用的内存,解除引用的真正作用是让值脱离执行环境,以便垃圾收集器下次运行将其回收
这一做法适用于大多数全局变量和全局对象的属性。局部变量会在它们离开执行环境时自动解除引用。


总结:

  1. 变量内存模型
  2. 参数传递只传值,变量访问有值访问和引用访问
  3. typeof和instanceof
  4. 执行环境和作用域链
  5. 垃圾收集器机制以及跟其相关的一些性能问题优化和内存管理
0 0