您现在的位置:首页 >> 前端 >> 内容

变量、作用域链和内存问题学习总结

时间:2017/3/24 9:11:46 点击:

  核心提示:理解变量和作用域链对于深入理解闭包有非常重要的作用,因此将变量和作用域(链)及涉及到的内存性能问题做一总结。一、变量在 ECMAScript中,变量可以分为 基本类型 和 引用类型 两种。这两种数据类...

理解变量和作用域链对于深入理解闭包有非常重要的作用,因此将变量和作用域(链)及涉及到的内存性能问题做一总结。

一、变量

在 ECMAScript中,变量可以分为 基本类型 和 引用类型 两种。

这两种数据类型 虽然都属于变量,但各自有不同的行为特点:

1. 基本类型 无法添加属性,即使添加,结果也为 undefined ,而引用类型却可以增删改查属性,自由自在。

var name = "Nicholas";

name.age = 21;

alert(name.age); //undefined

2. 变量复制

基本类型的变量复制 可以理解为 变量的副本克隆,复制后得到的新变量 与 旧有变量 是完全独立的个体,不会互相影响;

引用类型如 object 的复制,本质上是指针或引用的复制,真正的对象是存在于堆中,就好比:一对亲兄弟 都对老家的祖屋有所有权(指针均指向堆中的对象),那么如果 老大把祖屋拆坏了,那么“老二的”祖屋也势必会收到影响(势必会,因为都是同一间屋子),所以,引用类型的变量复制,如果一个变量发生变化,那么另一个变量也会发生变化。

如:

var obj1 = new Object();

var obj2 = obj1;

obj1.name = "Nicholas";

obj2.name = "张三";

alert(obj1.name); // 张三

3. 参数传递问题

函数的参数传递本质上就以看做 变量的复制过程。既然如此,面对基本类型和引用类型的变量在函数外部向内部传参的过程 实际上就是复制变量的过程。

对于引用类型 的变量而言,函数传参就是把这个值在内存中的地址(指针)复制给一个局部变量。即 函数内部局部变量的变化会反应到函数外部。如:

function setName(o) {

o.name = "Nicholas";

}

var person = {name:"lisi"};

setName(person);

alert(person.name); // Nicholas

但 如果 函数内部的这个局部变量如果指针之后又发生变化,那么变化不会反应到函数外部来。

看这个例子:

function setName1(o) {

o.name = "Nicholas";

o = new Object(); //引用指针已经发生变化,所以不会影响到外部对象

o.name = "vin";

}

var person = new Object();

setName1(person);

alert(person.name); // Nicholas

当然也可以理解为 此时 函数内部由于重写了对象,那么这个对象就是局部对象了,局部对象当然在函数执行完毕就被销毁了,影响到函数外部 就无从谈起了。

4. 类型检测

基本类型 使用 typeof ; 引用类型 使用 instanceof

注意:在对function 使用 typeof的时候 会返回 function

二、作用域链

究竟何为作用域链?

面试官经常会问道的一个问题,其实作用域链并不是什么特殊的存在,说白了,作用域链 就是 对象链(对象列表或指针列表) 而对象 则指的就是和执行环境(作用域)绑定在一起的变量对象(variable object) 。这个变量对象中存放的是当前代码所在的作用域中的所有变量 和 函数。而每个作用域都有这样的一个变量对象,众多的变量对象就形成了所谓的作用域链了。

理解作用域链的关键,我认为要理解 作用域链的前端存放的是当前代码执行环境的变量对象,因此,嵌套函数中,内层的函数可以通过作用域链访问到外部环境的变量和函数,因为 这些变量和函数都是在它内部函数的作用域链上可以找到的;而外部环境却无法直接访问内部环境的变量和函数, 因为外部环境的作用域链中只包含当前作用域中的变量对象和全局环境中的变量对象,即作用域链的前端无法触及内部环境,只包含当前代码执行环境的变量对象啊。

但也不是永远无法访问到内部环境的变量和函数了,有可以延长作用域链的 try-catch 语句和with 语句 ,也有 突破作用域链限制的 闭包(closure)。后续会持续更新总结。

三、内存问题

声明一个变量,就得消费内存中的一个空间。变量的数量如果很多,那么回收的工作量也是相当大的。为此,JavaScript 有自己专门的垃圾回收机制用来处理内存回收的。

目前,主流的垃圾回收机制是标记清除 。

内存问题是指 很多本来是要收回的内存却无法正常被垃圾回收机制收回,造成的原因之一就是全局变量和全局对象的循环引用所致。解决办法就是在程序当中把那些不用的

全局变量和对象及时赋值为null,告诉js的垃圾回收机制 这是不用的垃圾,然后垃圾回收机制就会到时自动回收了。熟悉php的同学都应该知道php中有个unset函数就是用来卸载变量的。道理是一样一样的。

作者:网络 来源:不详