资讯专栏INFORMATION COLUMN

《Javascript高级程序设计 (第三版)》第四章 变量、作用域和内存问题

szysky / 1970人阅读

摘要:在中虽然对象通过标记清除的方式进行垃圾收,但与对象却是通过引用计数回收垃圾的,也就是说只要涉及及就会出现循环引用问题。如果垃圾收集例程回收的内存分配量低于,则变量字面量和或数组元素的临界值就会加倍。

只挑本人重要的写(有夹杂其他补充)

基本类型和引用类型的值

描述:基本类型值指的是简单的数据段,而引用类型值指那些可能由多个值构成的对象。

动态的属性

引用类型的值,我们可以为其添加属性和方法,也可以改变和删除其属性和方法

var person = {};
person.name = "Nicholas";
alert(person.name); //"Nicholas"

不能给基本类型的值添加属性,尽管这样做不会导致任何错误

var name = "Nicholas";
name.age = 27;
alert(name.age); //undefined

复制变量

变量是基本类型的值时,会在变量对象上创建一个新值,然后把该值复制
到为新变量分配的位置上

var num1 = 5;
var num2 = num1;
此后,这两个变量可以参与任
何操作而不会相互影响

变量是引用类型的值时,同样也会将存储在变量对象中的值复制一份放到为新变量分配的空间中。这个值的副本实际上是一个指针,而这个指针指向存储在堆中的一个对象

var obj1 = new Object();
var obj2 = obj1;
obj1.name = "Nicholas";
alert(obj2.name); //"Nicholas"

传递参数
描述:所有函数的参数都是按值传递的。基本类型值复制,而引用类型值是按值

基本类型值复制

function addTen(num) {
    num += 10;
    return num;
}
var count = 20;
var result = addTen(count);
alert(count); //20,没有变化
alert(result); //30

引用类型值是按值

function setName(obj) {
    obj.name = "Nicholas";
}
var person = {};
setName(person);
alert(person.name); //"Nicholas"

function setName(obj) {
    obj.name = "Nicholas";
    obj = new Object();
    obj.name = "Greg";
}
var person = new Object();
setName(person);
alert(person.name); //"Nicholas"
说明即使在函数内部修改了参数的值,但原始的引用仍然保持未变。实际上,当在函数内部重写 obj 时,这
个变量引用的就是一个局部对象了。而这个局部对象会在函数执行完毕后立即被销毁。
执行环境及作用域

描述:定义了变量或函数有权访问的其他数据,决定了它们各自的行为。每个执行环境都有一个与之关联的变量对象(variable object),环境中定义的所有变量和函数都保存在这个对象中。
作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问

延长作用域链
有些语句可以在作用域链的前端临时增加一个变量对象,该变量对象会在代码执行后被移除。在两种情况下会发生这种现象。

try-catch 语句的 catch 块;
with 语句。

function buildUrl() {
    var qs = "?debug=true";
    with(location){
    var url = href + qs;
    }
    return url;
}
 with 语句内部,则定义了一个名为 url 的变量,因而 url 就成了函数执行环境的一
部分,所以可以作为函数的值被返回。

没有块级作用域
一个 if 语句中定义了变量 color 但在 JavaScript 中, if 语句中的变量声明会将变量添加到当前的执行环境(在这里是全局环境)中。(for 语句也一样)

if (true) {
var color = "blue";
}
alert(color); //"blue"

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

function add(num1, num2) {
    var sum = num1 + num2;
    return sum;
}
var result = add(10, 20); //30
alert

查询标识符
当在某个环境中为了读取或写入而引用一个标识符时,必须通过搜索来确定该标识符实际代表什么。搜索过程从作用域链的前端开始,向上逐级查询与给定名字匹配的标识符。如果在局部环境中找到了该标识符,搜索过程停止,变量就绪如果在局部环境中没有找到该变量名,则继续沿作用域链向上搜索。搜索过程将一直追溯到全局环境的变量对象。如果在全局环境中也没有找到这个标识符,则意味着该变量尚未声明

var color = "blue";
function getColor(){
    return color;
}
alert(getColor()); //"blue"
垃圾收集

描述:有自动垃圾收集机制,也就是说,执行环境会负责管理代码执行过程中使用的内存。

标记清除
这是JavaScript最常见的垃圾回收方式,当变量进入执行环境的时候,比如函数中声明一个变量,垃圾回收器将其标记为“进入环境”,当变量离开环境的时候(函数执行结束)将其标记为“离开环境”。 垃圾回收器会在运行的时候给存储在内存中的所有变量加上标记,然后去掉环境中的变量以及被环境中变量所引用的变量(闭包),在这些完成之后仍存在标记的就是要删除的变量了。

引用计数
在低版本IE中经常会出现内存泄露,很多时候就是因为其采用引用计数方式进行垃圾回收。引用计数的策略是跟踪记录每个值被使用的次数,当声明了一个变量并将一个引用类型赋值给该变量的时候这个值的引用次数就加1,如果该变量的值变成了另外一个,则这个值得引用次数减1,当这个值的引用次数变为0的时 候,说明没有变量在使用,这个值没法被访问了,因此可以将其占用的空间回收,这样垃圾回收器会在运行的时候清理掉引用次数为0的值占用的空间。 在IE中虽然JavaScript对象通过标记清除的方式进行垃圾收,但BOM与DOM对象却是通过引用计数回收垃圾的,也就是说只要涉及BOM及DOM就会出现循环引用问题

性能问题
IE 的垃圾收集器是根据内存分配量运行的,具体一点说就是 256 个变量、4096 个对象(或数组)字面量和数组元素(slot)或者 64KB 的字符串。达到上述任何一个临界值,垃圾收集器就会运行。这种实现方式的问题在于,如果一个脚本中包含那么多变量,那么该脚本很可能会在其生命周期中一直保有那么多的变量。而这样一来,垃圾收集器就不得不频繁地运行。结果,由此引发的严重性能问题促使 IE7 重写了其垃圾收集程。随着 IE7 的发布,其 JavaScript 引擎的垃圾收集例程改变了工作方式:触发垃圾收集的变量分配、字面量和(或)数组元素的临界值被调整为动态修正。IE7 中的各项临界值在初始时与 IE6 相等。如果垃圾收集例程回收的内存分配量低于 15%,则变量、字面量和(或)数组元素的临界值就会加倍。如果例程回收了 85%的内存分配量,则将各种临界值重置回默认值。这一看似简单的调整,极大地提升了 IE在运行包含大量 JavaScript 的页面时的性能。

管理内存
确保占用最少的内存可以让页面获得更好的性能。而优化内存占用的最佳方式,就是为执行中的代码只保存必要的数据。一旦数据不再有用,最好通过将其值设置为 null 来释放其引用——这个做法叫做解除引用(dereferencing)

解除引用的真正作用是让值脱离 执行环境,以便垃圾收集器下次运行时将其回收。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/89536.html

相关文章

  • 进击的 JavaScript(四) 之 闭包

    摘要:此时产生了闭包。导致,函数的活动对象没有被销毁。是不是跟你想的不一样其实,这个例子重点就在函数上,这个函数的第一个参数接受一个函数作为回调函数,这个回调函数并不会立即执行,它会在当前代码执行完,并在给定的时间后执行。 上一节说了执行上下文,这节咱们就乘胜追击来搞搞闭包!头疼的东西让你不再头疼! 一、函数也是引用类型的。 function f(){ console.log(not cha...

    Anleb 评论0 收藏0
  • JavaScript高级程序设计(第3版)》——变量作用域和内存问题(四)

    摘要:执行环境的类型有两种全局全局执行环境局部函数执行环境每个环境都可以向上搜索作用域链,以查询变量和函数名但任何环境都不能通过向下搜索作用域链而进入另一个执行环境。内部可通过作用域链访问外部,外部不能访问内部。 变量、作用域和内存问题 ECMAScript 数据类型 基本类型(5种): Undefined,Null,Boolean,Number,String typeof() 检测...

    YacaToy 评论0 收藏0
  • JavaScript 闭包

    摘要:闭包的注意事项通常,函数的作用域及其所有变量都会在函数执行结束后被销毁。但是,在创建了一个闭包以后,这个函数的作用域就会一直保存到闭包不存在为止。最后通过释放了和对闭包的引用。从而使用闭包模块化代码,减少全局变量的污染。 JavaScript 闭包 原文链接 什么是闭包(Closure) 简单讲,闭包就是指有权访问另一个函数作用域中的变量的函数。 MDN 上面这么说:闭包是一种特殊的...

    zhou_you 评论0 收藏0
  • 图解JS闭包形成的原因

    摘要:闭包的出现正好结合了全局变量和局部变量的优点。这就是闭包的一个使用场景保存现场。 前言 什么是闭包,其实闭包是可以重用一个对象,又保护对象不被篡改的一种机制。什么是重用一个对象又保护其不被篡改呢?请看下面的详解。 作用域和作用域链 注意理解作用域和作用域链对理解闭包有非常大的帮助,所以我们先说一下作用域和作用域链 什么是作用域作用域表示的是一个变量的可用范围、其实它是一个保存变量的对象...

    wind3110991 评论0 收藏0
  • 四章 变量作用域和内存问题

    摘要:如果在局部环境没有找到该变量名,则继续沿作用域链向上搜索。很明显,访问局部变量要比访问全局变量更快,因为不用向上搜索作用域链。 按照ECMA-262定义,JavaScript的变量松散类型的本质,决定了: 它还只是在特定时间用于保存特定值的一个名字而已。 变量的值及其数据类型可以再脚本的生命周期内改变。 4.1 基本类型和引用类型的值 基本类型 简单的数据段(Undefine...

    AlphaWatch 评论0 收藏0

发表评论

0条评论

szysky

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<