JS变量,作用域,和内存问题
4.JS变量,作用域和内存问题
1.基本类型和引用类型的值;
ECMAScript 变量可能包含两种不同的数据类型的值:基本类型值和引用类型值。
基本类型值为简单的数据段,而引用类型值为由多个值构成的对象。
在将一个值赋值给变量时,解析器必须确定这个值时基本类型还是引用类型的值。
例如简单的五种基本类型的值:undefined,null,number,string,boolean, 这五种时基本类型的值,时按值访问的,可以操作变量中实际的值。
引用类型的值(object,function,Array,date)是保存在内存中的对象,js不允许直接访问内存的地址,在操作对象时,实际上时在操作对象的的引用,而不是实际的对象。即不能操作对象的内存空间。
2.动态的属性
引用类型的值可以添加属性或者方法。
var person = new object();
Person.name = “tom”;
而基本类型的值不能添加属性或者方法。删除或者覆盖是不能改变的。
基本类型的值在定义之后除了
这说明只能给引用类型动态的添加属性,以便将来使用。
3.赋值变量值
赋值基本变量值时,会在变量对象上创建一个新值,然后把该值赋值给新变量分配的位置上。
Num1 ,num2 中保存的两个5 是完全独立的,两个变量可以参与任何操作而且不会相互影响。
赋值引用类型的值时:
引用类型复制的其实是该obj1在堆内存中的引用地址。
javascript的引用数据类型是保存在堆内存中的对象。与其他语言的不同是,你不可以直接访问堆内存空间中的位置和操作堆内存空间。只能操作对象在栈内存中的引用地址。
所以,引用类型数据在栈内存中保存的实际上是对象在堆内存中的引用地址。通过这个引用地址可以快速查找到保存中堆内存中的对象。
var obj1 = new Object();
var obj2 = obj1;
obj2.name = "我有名字了";
console.log(obj1.name); // 我有名字了
说明这两个引用数据类型指向了同一个堆内存对象。obj1赋值给obj2,实际上这个堆内存对象在栈内存的引用地址复制了一份给了obj2,
但是实际上他们共同指向了同一个堆内存对象。实际上改变的是堆内存对象。
引用类型在栈空间中显示为一个标识符和一个地址;
结论;
4.传递参数
ECMAScript中所有函数的参数都是按值传递的
但是为什么涉及到原始类型与引用类型的值时仍然有区别呢?还不就是因为内存分配时的差别。
1)原始值:只是把变量里的值传递给参数,之后参数和这个变量互不影响。
2)引用值:对象变量它里面的值是这个对象在堆内存中的内存地址.因此它传递的值也就是这个内存地址,这也就是为什么函数内部对这个参数的修改会体现在外部的原因了,因为它们都指向同一个对象。
5.检测类型
Instanceof()
例如:
A instanceof object // ture /false
var obj1 = Object();
alert(obj1 instanceof Object);
5.执行环境和作用域
<script>
//执行环境 window对象 (最上层的执行环境) 下面所有定义的函数,或者变量均为window对象的属性或方法。
var color1 = 'blue';
function changecolor() //每一个函数都有一个执行环境 并且有一个与之关联的变量对象 (variable obj)
{
var color2 = 'red';
//color3 3级作用域 ,color2 2级作用域,color1,1级作用域。
function swapcolor() //这个函数又产生一个执行环境(variable obj)
{
var color3 = color2;
color2 = color1;
color1 = color3;
//在这里可以访问 color1,color2,color3,
}
//在这里可以访问color1,color2.
swapcolor();
}
//在这里只能访问color1.
changecolor();
</script>
1.环境变量可以 一级一级向上追溯,可以访问他的上级环境(包括变量和函数)
2.因为是一级一级向上追溯,所以访问速度较慢,一般项目不会采用全局变量。
3.内部环境可以通过作用域链来向上搜索,访问外部环境中的变量和函数,而外部环境则不能向下搜索访问内部环境的变量和函数。
4.在这里swapcolor()的执行环境中,将color1看作为一个标识符,如果在swapcolor()的局部环境中找到了color1,则搜索停止,如果没有找到,则通过作用域链向上搜索,搜索过程将一直追溯到全局环境的变量对象,如果全局环境中一九未找到该变量,则说明该变量尚未声明。
关于延长作用域链:
使用 try-catch 语句中的 catch块 ;
或者 使用 with语句;
6.没有块级作用域
<script>
for(i=0;i<10;i++)
{
i += 1;
}
//alert(i); //10
if(true)
{
var a = 10;
}
alert(a); //10
</script>
在js中if语句中的变量声明会添加到当前的执行环境中。
而对于for语句而言,有块级作用域的话,for语句中定义的变量只会存在于其循环中,
而对于 js 而言不存在会计作用域,当i在for语句中执行完之后依旧会出现在外部环境中。
而当不使用var 声明变量时,会自动添加到全局变量中。
7.内存管理
为了确保web浏览器占用字少的内存以便让web浏览器有更好的性能。就是为执行张的代码只保存必要的数据,一旦数据不再有用,最好同过将其值设为null来释放其引用,这个方法叫做解除引用。
例如:
<script>
function sum(a,b)
{
alert (a+b);
}
var qiuhe = sum(10,5);
qiuhe = null; // 解除引用;
</script>