首页 > 代码库 > 变量、作用域和内存问题
变量、作用域和内存问题
1 基本类型和引用类型的值
ECMAScript可能包含两种不同数据类型的值:
- 基本类型值——简单的数据段
- 引用类型值——可能由多个值构成的对象
1.1 动态的属性
可以动态地为引用类型值添加或删除属性和方法:
var person = new Object(); person.name = "Nicholas"; alert("person.name"); //"Nicholas"
不能给基本类型添加属性,尽管不会导致任何错误:
var name = "Nicholas"; name.age = 27; alert("name.age"); //undefined
1.2 复制变量值
基本类型:创建的是原来变量的一个副本,是两个完全独立的变量,修改其中之一不会影响另一个。
var num1 = 5; var num2 = num1; num1 = 10; alert("num1"); //10 alert("num2"); //5
引用类型:创建的是对象的指针,指向原来的变量指向的对象。改变其中一个变量会影响另一个变量。
var obj1 = new Object(); var obj2 = obj1; obj1.name = "Nicholas"; alert(obj2.name); //"Nicholas"
1.3 传递参数
ECMAscript中所有函数的参数都是按值传递的。基本类型的传递和基本类型复制一样,而引用类型传递即和引用类型复制一样。
基本类型:
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"; //这里的obj为传入的参数的一个(指针)副本,其指向传入参数指向的对象,可以用其来为其指向的对象添加属性。 } var person = new Object(); setName(person); alert(person.name); //"Nicholas
1 function setName(obj) { 2 obj.name = "Nicholas"; //obj指向的对象与传入参数指向的对象相同,这里obj为其指向的对象添加了name属性 3 obj = new Object(); //obj指向了一个新的局部对象 4 boj.name = "Greg"; //为这个局部对象添加name属性 5 } //脱离了作用域,obj指向的局部对象被销毁 6 7 var person = new Object(); 8 setName(person); 9 alert(person.name);
检测类型:
typeof操作符:
1 var u; 2 var n = null; 3 var o = new Object(); 4 5 alert(typeof u); //undefined 6 alert(typeof n); //object 7 alert(typeof o); //object
typeof检测函数时返回"function"。在Safari5及之前版本与chrome及之前版本用typeof检测正则表达式返回"function",因为ECMA-262规定任何内部实现了[[Call]]方法的对象在应用typeof操作符时返回"function"。
而在IE和Firefox中对正则表达式应用typeof返回“object”。
instanceof操作符:
语法: result = variable instanceof constructor
如果变量是给定引用类型(根据它的原型链来识别)的实例,那么instanceof操作符就返回true。
2 执行环境及作用域
内部作用域可以访问外部作用域的局部变量,反之则不能。函数参数被当作变量来对待,因此其访问规则与作用域中其他变量的访问规则相同。
2.1 延长作用域链
当执行流进入下列任何一个语句时,作用域链就会得到加长:
- try-catch语句的catch块
- with语句
2.2 没有块级作用域
在if语句和for语句中的变量声明会将变量添加到当前的执行环境,这点与其他类C语言不同。
1 if (true) { 2 var color = "blue"; 3 } //在C、C++等语言中,此时color因离开作用域而被销毁,但是javascript中不会。 4 5 alert(color); //"blue" 6 7 for (var i = 0; i < 10; ++i) { 8 doSomething(i); 9 } // 在C、C++等语言中,此时 i 因离开作用域而被销毁,但是javascript中不会。 10 alert(i); //10
变量声明:var声明的变量会被自动添加到就近环境。初始化变量没有使用var声明,变量会被自动添加到全局环境。
!!!不声明而直接初始变量是一个常见的错误做法,因为可能导致意外。建议在初始化变量之前一定要声明变量。
查询标识符:标识符查询是从内往外逐层查询,直到找到标识符或搜索到全局作用域为止。一旦找到标识符,立即停止搜索。内层作用域的同名变量会覆盖外层作用域的同名变量。
3 垃圾收集
JavaScript具有自动垃圾手机机制,通常有两种策略:
- 标记清除:垃圾收集器在运行的时候给存储在内存中的变量都加上标记,然后去掉环境中的变量以及被环境中变量引用的变量的标记,在此之后再被标记的变量将被视为准备删除的变量。
- 引用计数:值被引用或复制时引用计数加1,而包含对这个值的引用的变量取得另一个值时引用次数减1。当引用计数为0时内存将被释放。(不常用)
IE7垃圾回收例程工作方式:如果垃圾收集例程回收的内存分配量低于15%,则变量、字面量和元素数组的临界值会加倍。如果内存回收了85%的内存分配量,则将各种临界值重置回默认值。
变量、作用域和内存问题