《JavaScript 高级程序设计》总计四(2)

引言:这一节我们对执行环境及作用域以及JavaScript的内存、垃圾机制等进行总结。

执行环境:执行环境(或者直接称:环境)是JavaScript 中最为重要的一个概念,执行环境定义了变量或函数有权访问的其他数据,决定了他们的各自行为。每个执行环境都有一个与之关联的 变量对象 ,环境中定义的所有变量和函数都保存咋这个对象中。虽然我们编写的代码无法访问这个对象,但是解析器在处理数据时会在后台使用它。

全局执行环境是最外层的一个环境,在WEB浏览器中,全局执行环境被认为是 window 对象,因此也可以认为所有全局变量和函数都是作为 window 对象的属性和方法创建的。某个执行环境中所有代码执行完毕后该环境销毁,保存在其中的所有变量和函数定义也随之销毁(全局执行环境直到应用程序退出——例如关闭网页或浏览器时才会被销毁)。

作用域链:当代码在一个环境中执行时,会创建变量对象的一个作用域链,作用域链的作用就是保证执行环境有权访问的所有变量和函数的有序访问。作用域链的前端始终是当前执行的代码所在环境的变量对象。如果这个环境是函数,则将其活动对象作为变量对象。活动对象在最开始只包含一个变量,即 arguments 对象(这个对象在全局环境中是不存在的)。在作用域链中的下一个变量对象来自包含(外部)环境,而再下一个对象则来自下一个包含环境,这样一直延续到全局环境,全局执行环境的变量对象始终是作用域链中的最后一个对象。这句话有些绕难以理解,我们直接看例子:

                            

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

以上涉及三个执行环境,即全局变量环境、changeColor() 的局部变量环境,还有 swapColors()的局部变量环境。而从上面的例子也能够看出。这个执行的的作用域链是由内部到外部的也就是上面提到的“用域链中的下一个变量对象来自包含(外部)环境,而再下一个对象则来自下一个包含环境,这样一直延续到全局环境”。通过这样的方式,内部函数可以使用外部函数的变量以及全局的变量,但是反过来,我们在外部不能直接访问到内部函数的变量。这之后也就出现了闭包(之后我们会总结)

延长作用域链 :当执行函数流入下列任何一个语句时,作用域链就会得到加长:1、try—catch 语句的 catch 块  2、with语句。

举个栗子:

function buildUrl(){
var qs="?debug=true"
with(location){
var url =href+qs;
}
return url;
}

                                    

在这里 with 接收的是location 对象,因此其变量中就包含了location 对象的所有属性和方法,而这个对象呗添加到了作用域前端。因此在这里我们就可以引用到 变量qs 。至于with 语句内部,则定义了一个url 变量,所以 url 就成了函数执行环境的一部分,所以就可以作为函数的值被返回。

ps (在IE8及其之前的版本,cath 的错误对象会被添加到执行环境中而不是在catch 的环境中,所以会出现在IE8 及其之前的版本中可以在catch 外部访问错误对象的情况,这种问题在IE9 以及得以修复)。

垃圾回收机制:

JavaScript 具有垃圾回收机制,也就是说,执行环境会负责管理代码执行过程使用的内存。这种垃圾回收机制实现原理很简单:找出那些不用的变量,然后释放其占用的资源。为此,垃圾收集器会按照固定时间间隔(或代码执行中预定的收集时间周期性的执行这一操作)。

局部变量的正常生命周期:局部变量只在函数执行的过程中存在,而在这个过程中,会为局部变量在栈(或堆)上分配相应的空间,以便储存它的值。然后在函数中使用这些变量,直至函数结束,此时,局部变量就没有存在的必要了,因此可以释放他们的内存。在这种情况下很容易判断变量是否有存在的必要,但是,并非所有情况都那么容易得出结论。垃圾收集器必须跟踪哪个变量有用哪个没用。对于不在有用的变量打上标签,以便后面释放其资源。用于标识无用变量的策略可能会因时实而异,但是具体到浏览器中实现,则有两种情况:

1、标记清除:   这是JavaScript最常见的垃圾回收方式,当变量进入执行环境的时候,比如函数中声明一个变量,垃圾回收器将其标记为“进入环境”,当变量离开环境的时候(函数执行结束)将其标记为“离开环境”。至于怎么标记有很多种方式,比如特殊位的反转、维护一个列表等,这些并不重要,重

要的是使用什么策略,原则上讲不能够释放进入环境的变量所占的内存,它们随时可能会被调用的到。

   垃圾回收器会在运行的时候给存储在内存中的所有变量加上标记,然后去掉环境中的变量以及被环境中变量所引用的变量(闭包),在这些完成之后仍存在标记的就是要删除的变量了,因为环境中的变量已经无法访问到这些变量了,然后垃圾回收器相会这些带有标记的变量机器所占空间。

大部分浏览器都是使用这种方式进行垃圾回收,区别在于如何标记及垃圾回收间隔而已,只有低版本IE,不出所料,又是IE。。。

2、引用计数:另一种不太常见的垃圾回收策略是引用计数。引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型赋值给该变量时,则这个值的引用次数就是1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数就减1。当这个引用次数变成0

时,则说明没有办法再访问这个值了,因而就可以将其所占的内存空间给收回来。这样,垃圾收集器下次再运行时,它就会释放那些引用次数为0的值所占的内存。

  引用计数这个方式很容易理解,但是在使用时会碰上一个问题,那就是循环引用:

    function pro(){

    var a=new Object();

    var b=new Object();

    a.Obj=b;

    b.obj=a;

}  在这个函数中,a、b通过各自的属性相互引用。也就是说二者的引用次数都是2。 这就很尴尬了,当函数执行完毕后,二者的引用次数都不是0,那么这时候引用计数的方式就不行了。如果这个方法被执行多次,那么里面的变量就会堆积,这不是我们想要看到的结果。

    

 我们知道,IE中有一部分对象并不是原生JavaScript对象。例如,其BOM和DOM中的对象就是使用C++以COM(Component Object 
Model,组件对象)对象的形式实现的,而COM对象的垃圾回收器就是采用的引用计数的策略。因此,即使IE的Javascript引擎使用标记清除的策略来实现的,但JavaScript访问的COM对象依然是基于引用计数的策略的。说白了,只要IE中涉及COM对象,就会存在循环引用的问题。看看下面的这个简单的例子:

var element = document.getElementById("some_element");
var myObj =new Object();
myObj.element = element;
element.someObject = myObj;

  上面这个例子中,在一个DOM元素(element)与一个原生JavaScript对象(myObj)之间建立了循环引用。其中,变量myObj有一个名为element的属性指向element;而变量element有一个名为someObject的属性回指到myObj。由于循环引用,即使将例子中的DOM从页面中移除,内存也永远不会回收。
        
  不过上面的问题也不是不能解决,我们可以手动切断他们的循环引用。

myObj.element = null;
element.someObject =null;

  这样写代码的话就可以解决循环引用的问题了,也就防止了内存泄露的问题。

  不过为了解决上述问题,IE9 把BOM 和DOM 对象都转成真正的JavaScript对象。这样就避免了两种垃圾回收算法并存导致的问题。也就防止了内存泄露的问题。

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

本章完。下一章预告:

引用类型。

我们知道JavaScript中有两种类型,数据类型和引用类型。前面的总结已经让我们对基础数据类型有了了解,接下来让我们走进引用类型的世界。

原文地址:https://www.cnblogs.com/wxhhts/p/9426240.html

时间: 2024-10-20 15:33:18

《JavaScript 高级程序设计》总计四(2)的相关文章

JavaScript高级程序设计学习(四)之引用类型

在javascript中也是有引用类型的,java同样如此. javascript常见也比较常用的引用类型就熟Object和Array. 一个对象和一个数组,这个在前后端分离开发中也用的最多.比如ajax传参,有时我不仅仅只是需要一个参数,例如添加方法,传的是一个对象,对象存在属性.在java中对象也可以说类.因为类存在属性,例如人类,他的属性有身高,体重,姓名,年龄,性别等.而js对象,也可以这样,比如车,它可以有品牌,颜色,造型等等. js对象可以做什么呢?同java对象有什么区别呢? 第一

读书时间《JavaScript高级程序设计》四:BOM,客户端检测

隔了一段时间,现在开始看第8章. 第8章:BOM BOM提供了很多对象,用于访问浏览器的功能.BOM的核心对象是window,它表示浏览器的一个实例. window对象是通过javascript访问浏览器窗口的一个接口,又是ECMAScript中的Global对象. 所有在全局作用域声明的变量.函数都是window对象的属性和方法. 1. 窗口关系,框架 每个框架都有window对象,并在frames集合中 每个window对象都有name属性,其中包含框架名称 top对象始终指向最高(最外)层

javascript高级程序设计第四章 变量、作用域和内存问题

变量包含两种,,基本类型和引用类型 基本类型是指一些简单的字段: 引用类型是?由多个值构成的对象  引用类型的值是保存在内存中的对象,在javascript中是不允许直接访问内存中的位置; 函数的参数是按照值类型进行传递的,函数的参数可以看作是一个局部变量. 检测类型: typeOf  用来检测基本类型的值用处大,在检测引用类型的值得时候用处不是很大  检测到的Null类型返回结果为Object, insctanceof 用来检测引用类型的值,当检测的对象是引用类型的值或者Object时返回tr

JavaScript高级程序设计第四版(let 声明、临时死区、全局声明、条件声明)

let 声明 let的操作与var几乎相同的,但是有一些重要的区别.最需要注意的是: let是块作用域,而var是函数作用域的. if (true) {    var name = 'Matt';    console.log(name); //Matt } console.log(name); //Matt if (true) {     let age = 26;     console.log(age); //26 } console.log(age); //Uncaught Refere

JavaScript高级程序设计-第四章-变量、作用域和内存问题

ECMAScript变量 基本类型:5 引用类型 存于内存栈 实际对象位于内存堆 按值访问,可操作保存在变量中实际的值 js不能直接操作对象的内存空间,而是操作它的引用 不可添加属性和方法 可添加属性和方法 变量复制是一个实际的值,互不干扰 变量复制是一个指针,指向相同的对象,改变其中一个变量会影响另一个 Undefined   Null   Boolean   Number   String           variable typeof v v instanceof constructo

javascript高级程序设计 第十四章--表单脚本

javascript高级程序设计 第十四章--表单脚本 在HTML中表单由<form>元素表示,在js中表单对应的是HTMLFormElement类型,这个类型也有很多属性和方法:取得表单元素的引用还是为它添加id特性,用DOM操作来获取表单元素:提交表单:把<input>或<button>元素的type特性设置为"submit",图像按钮把<input>元素的type特性设置为"image",也可以调用submit(

《Javascript高级程序设计》阅读记录(二):第四章

这个系列之前文字地址:http://www.cnblogs.com/qixinbo/p/6984374.html 这个系列,我会把阅读<Javascript高级程序设计>之后,感觉讲的比较深入,而且实际使用价值较大的内容记录下来,并且注释上我的一些想法.做这个一方面是提升了我的阅读效果以及方便我以后阅读 另一个目的是,Javascript高级程序设计这本书内容很多也很厚,希望其他没有时间的人可以通过看这系列摘录,就可以大体学到书里面的核心内容. 绿色背景的内容是我认为比较值得注意的原著内容.

《Javascript高级程序设计》阅读记录(四):第五章 下

这个系列,我会把阅读<Javascript高级程序设计>之后,感觉讲的比较深入,而且实际使用价值较大的内容记录下来,并且注释上我的一些想法.做这个一方面是提升了我的阅读效果以及方便我以后阅读 另一个目的是,Javascript高级程序设计这本书内容很多也很厚,希望其他没有时间的人可以通过看这系列摘录,就可以大体学到书里面的核心内容. 绿色背景的内容是我认为比较值得注意的原著内容. 黄色背景的内容是我认为非常重要的原著内容. 我的理解会用蓝色的字体标示出来. 这章的内容较多,而且比较重要,分两篇

《JavaScript高级程序设计》学习笔记(5)——面向对象编程

欢迎关注本人的微信公众号"前端小填填",专注前端技术的基础和项目开发的学习. 本节内容对应<JavaScript高级程序设计>的第六章内容. 1.面向对象(Object-Oriented, OO)的语言有一个标志,那就是它们都有类的概念,而通过类可以创建任意多个具有相同属性和方法的对象.前面提到过,ECMAScript中没有类的概念,因此它的对象也与基于类的语言中的对象有所不同. ECMA-262把对象定义为:"无序属性的集合,其属性可以包含基本值.对象或者函数.

JavaScript高级程序设计(第三版)学习,第一次总结

Array类型 var arr = []; arr.length; //返回数组元素个数 改变length可以动态改变数组大小 检测数组 instanceof可以检测某个对象是否是数组,限制:只能是一个网页或一个全局作用域 Array.isArray(arr); //最终确定某个值到底是不是数组,没有限制 转换方法 arr.toString(); //返回由数组每个值的字符串形式拼接而成的以逗号分隔的字符串 arr.valueOf(); //与toString方法一致 arr.toLocalSt