JS学习笔记整理二 变量、作用域和内存问题

168 阅读4分钟

变量、作用域和内存问题

基本类型和引用类型

基本类型和引用类型的区别。对保存对象的变量进行复制,操作的是对象的引用。但是添加对象的属性,操作的就是实际的对象。基本类型无法动态添加属性。这里涉及到昨天说的包装对象的问题。基本类型是存在栈内存中的。引用类型是存在堆内存,其在堆内存的地址存在栈内存。

Ecmascript中所有函数的参数都是按值传递的,而不是引用。即便是作为引用类型的对象,其实也是值传递。虽然在函数内修改对象的属性会反映到实际的对象中。但重写形参,并不会反映到原始的引用。(红皮书71p证明)因为是值传递,形参保存的是对象的引用地址,因此重写形参必然会断开与原始对象的联系。

检测类型,之前学到typeof,可以很方便的检测出number,string,boolean,undefined。但是null会检测为object。这是针对基本类型,但是很多时候我们需要查看的是对象的类型。这时候需要用instanceof操作符。和typeof一样也是关键字哦,所以不需要驼峰写法。

变量 instanceof 类型    //结果返回布尔值。

执行环境及作用域

执行环境也叫执行上下文。每个执行环境都对应一个变量对象variable object。

var color="blue";
function changecolor(color){
    color="orange";
}
changecolor(color);
console.log(color);//blue
 

var color="blue";
function changecolor(){
    color="orange";
}
changecolor();
console.log(color);//orange

作用域链永远都是从内而外的搜索,永远都是单向、线性的。

延长作用域链

with和try-catch可以延长作用域链。

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

try-catch块中

try{
    doSomething();
}catch(ex){
    alert(ex.message); //作用域链在此处改变
}

在发生异常进入catch代码段时。异常对象被推入新的变量对象并置于作用域链最前端。而catch代码段内的局部变量则进入到下一个执行环境的变量对象中。因此,catch内的代码量较多时性能会下降。解决的办法就是委托其他函数进行处理。如:

try{
    doSomething();
}catch(ex){
    handleError(ex); //作用域链在此处改变
}

同时,我们也通过这个例子了解了,为什么常说要少用全局变量。因为全局变量在作用域链的最后,会造成性能问题。

有一个技巧,当多次引用一个全局变量时,我们可以将其先保存为局部变量,再调用这个局部变量。这也是我们在一些框架里经常看到的写法。

没有块级作用域

使用var声明的变量会自动添加到最接近的环境中。所以在with中创建的变量会加入到其函数环境内。而并不像一些文章说的所谓返回

初始化未声明的变量在严格模式会报错。非严格模式会成为全局变量。

垃圾收集 GC

Javascript有自动垃圾收集机制。

主要的方式是标记清除(mark-and-sweep并列关系)。 当变量进入环境,则标记其“进入环境”,有次标记的变量都是不能释放的。当其离开环境,则标记其“离开环境”。

不常见的方式是引用计数。引用计数存在一些严重的问题,比如循环引用,两个对象互相引用,导致引用计数永远不为0,无法得到回收。在ie9以前,dom-js存在内存泄露的问题就是由循环引用引起的。如果想彻底回收对象,则可以断开引用。即将涉及循环引用的变量赋值null,即可消除。

垃圾收集器是周期运行的,因此确定垃圾收集的时间间隔非常重要。Ie早期是根据内存分配量的一组阈值运行的,当超过时就启动。但如果一个脚本本身就需要那么多,垃圾收集就会频繁触发。Ie7以后变为动态修正阈值。

Javascript有自动垃圾收集机制,一般不用在意内存分配和回收。但是系统分配给浏览器的资源通常比较少,因为担心js耗尽所有系统内存导致崩溃。所以在编程时要注意:针对全局变量和全局对象的属性,在不用的时候主动赋值null。以便垃圾收集下一次回收释放内存。函数环境的局部变量执行完毕就会自动解除引用。

给不用的变量或属性主动赋值null,一方面消除循环引用,一方面利于垃圾收集。

红皮书(js高程)82p的总结很精炼,很有帮助。