变量作用域和内存问题
Posted niusan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了变量作用域和内存问题相关的知识,希望对你有一定的参考价值。
//javascript高级程序设计读书笔记
1,基本类型和引用类型的值
基本类型值:简单的数据段。有5种基本数据类型,Undefined,Null,Boolean,Number和String;它们的值保存在栈内存。基本类型是按值访问的,所以我们操作的是保存在变量中的实际值。
引用类型值:JavaScript不能直接操作对象的内存空间,实际上是操作对象的引用,而不是实际的对象。引用类型的值是按引用访问的。查询引用类型的变量时,先从栈内存读取内存地址,然后根据地址找到堆内存中的值。
1.1 动态的属性
引用类型值的属性和方法可以修改:
var persion = new Object();
persion.name="Nicholas";
alert(persion.name); //"Nicholas"
基本类型值不能添加属性和方法:
var name ="Nicholas";
name.age=27;
alert(name.age); //undefined
1.2 复制变量值
基本类型:一个变量向另一个变量复制,会在变量对象上创建一个新值,然后把该值复制到为新变量分配的位置上,两个变量互不影响。
引用类型:同样会将存储在栈中的值复制一份到为新变量分配的空间中。不同的是这个值实际上就是一个指针,指针指向的是堆内存中的一个对象,两个变量实际上指的是同一个对象,改变其中的一个变量就会影响另一个。
1.3 传递参数
JS中所有函数的参数都是按照值传递的。
//基本类型是按值传递的。
function add(num){
num +=10;
return num;
}
var count = 20;
var result = add(count);
alert(count); //20没有变化
alert(result); // 30
//引用类型也是按值传递的,这个值是对象在内存中的地址值。
function setName(obj){
obj.name="Bob";
obj = new Object(); //重新定义了一个对象,obj的值改变,obj指向一个新的对象。
obj.name = "Greg"; //为该对象定义了一个不同值得name属性。此时和persion不是
同一个对象
}
var persion = new Object();
setName(persion); //persion和obj指向同一个对象,
alert(persion.name); // "Bob"
1.4 检测类型
typeof 操作符,确定一个变量是string,number,boolan,还是undefined。如果是对象或者null返回object;如果是函数返回function。
var s = "Hellow World";
console.log(typeof s); //string
instanceof操作符,确定一个变量是什么类型的对象。如果检测基本类型值,返回false
var arr =[1,2,3];
console.log(arr instanceof Array);//true
2,执行环境及作用域
执行环境定义了变量或函数有权访问的其他数据。每个环境都有与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。//全局环境被认为是window对象,所有的全局变量和函数都作为window对象的属性和方法创建的。
// 函数的环境在函数执行之后,栈将其环境弹出,
内部环境可以通过作用域链访问所有的外部环境,但外部环境不能访问内部环境中的任何变量和函数。每个环境都可以向上搜索作用域链,任何环境都不能向下搜索作用域链而进入另一个执行环境。
2.1 延长作用域链
//try-catch 语句 和 with 语句,这两个语句都会在作用域链的前端添加一个变量对象。使作用域链得到加长。with语句将指定对象添加到作用域链中,catch会创建一个新的变量对象。
function buildUrl() {
var qs = "?debug=true";
with(location) { //with将location对象放添加到作用域链中,
//当前环境可以访问location中的变量和方法
var url = href + qs;
}
return url;
}
console.log(buildUrl());
2.2 没有块级作用域
if (true) {//if语句中的变量声明会将变量添加到当前的执行环境
var color = "blue";
}
console.log(color); //"blue"
for (var i =0; i< 10 ; i++) {
var s = i; //即使for循环结束后,也依旧会存在于循环外部的执行环境中。
}
console.log("s的值为"+s); //s的值为9
console.log("i的值为"+i);//i的值为10
function add(num1,num2) {
var sum = num1+num2;
return sum;
}
var result = add(10,20); //30
console.log(sum); //由于sum不是有效变量,会报错。sum is not defined
//初始化赋值时没有使用var关键字,会将变量添加到全局环境中
function add1(sum1, sum2) {
he = sum1 + sum2;//初始化时没有使用var关键字,he成为全局变量。
return he;//在严格模式下,初始化未经声明的变量会导致错误。
//不声明而直接初始化也可能导致意外,一定要先声明在使用。
}
var result1 = add1(10, 20);//30
console.log(he); //30
3,垃圾收集
js有自动垃圾收集机制,执行环境会负责管理代码执行过程中使用的内存。原理:找到不再继续使用的变量,然后释放其占用的内存。垃圾收集器会按照固定的时间间隔,周期性的执行这一操作。
标记清除:垃圾收集器在运行的时候会给存储在内存中的每个变量都加上标记,然后去掉环境中的变量和被环境中变量引用的变量的标记,销毁那些仍带有标记的值并回收他们所占用的内存空间。
引用计数:跟踪记录每个值被引用的次数。垃圾收集器运行时会释放那些引用次数为0的值所占用的内存。
4,管理内存
确保占用最少的内存可以让页面获得更好的性能,而优化内存占用的最佳方式,就是为执行中的代码只保存必要的数据。一旦数据不再有用,最好通过将其值设置为null来释放其引用。解除引用这一做法适用于大多数全局变量和全局对象的属性。局部变量会在他们离开执行环境时被自动解除引用。
function createPerson(name) {
var localPerson = new Object();
localPerson.name=name;
return localPerson;
}
var globalPerson =createPerson("Bob");
//手动解除globalPerson的引用
globalPerson=null;
以上是关于变量作用域和内存问题的主要内容,如果未能解决你的问题,请参考以下文章