JavaScript变量松散类型的本质,决定了它只是在特定时间用于保存特定值的一个名字而已。由于不存在定义某个变量必须要保存何总数据类型值的规则,变量的值及其数据类型可以在脚本的生命周期内改变。
1.基本类型和引用类型的值
ECMAScript可能有两种不同数据类型的值:基本类型值和引用类型值。基本类型值指的是那些保存在栈内存中的简单数据段,即这种值完全保存在内存中的一个位置(基本数据类型有5种:undefined,null,boolean,number和string)。而引用类型值则是指那些保存在堆内存中的对象(变量中保存的实际上是一个指针,指向内存中的另一个位置)
五种基本类型的在内存中分别有固定大小的空间,因此可以把他们的值保存在栈内存中(这样也可以提高查询变量的速度),保存基本类型值的变量是按值访问。如果赋给变量的是一个引用类型的值,则必须在堆内存中为这个值分配空间。这种值的大小不固定,因此不能把他们保存到栈内存中。但内存地址的大小是固定的,因此可以将内存地址保存在栈内存中。查询引用类型的变量时将按引用访问(首先从栈中读取内存地址)
1.1动态属性
基本类型值和引用类型值的定义是类似的:创建一个变量并给该变量赋值。但是,当这个值保存到变量中以后,对不同类型值可以执行的操作则不同,对于引用类型的值,我们可以为其添加属性和方法,也可以改变和删除其属性和方法。不过不能给基本类型的值添加属性。
1.2复制变量值
除了保存的方式不同之外,在从一个变量向另一个变量复制基本类型值和引用类型值时也存在不同。基本类型值的复制过程中,会在栈中创建一个新值,然后把该值复制到新变量分配的位置上。
如:
var num1=5;
var num2=num1;
num2与num1值都是5,不过这两个值是独立的。
而在引用类型中,复制会将存储在栈中的值复制一份放到新的变量分配空间中,不过这个值的副本实际上是一个指针,这个指针指向存储在堆中的一个对象,复制操作结束后,这两个变量实际上将引用同一个对象。
如:
var obj1=new object();
var obj2=obj1;
obj1.name="ni";
alert(obj2.name);//"ni"
obj1和obj2指向的是同一个对象
1.3传递参数
ECMAScript中所有函数的参数都是按值传递的。
1.4检测类型
var s="ni";
var b=true;
var i=22;
var u;
var n=null;
var o=new Object();
使用typeof操作符输出的结果为:
alert(typeof s);//string
alert(typeof b);//boolean
alert(typeof i);//number
alert(typeof u);//undefined
alert(typeof n);//object
alert(typeof o);//object
在检测引用类型时,如果想知道它是什么类型的对象。就要用到instanceof操作符(书上的例子感觉没用)
2.执行环境及作用域
全局执行环境时最外围的一个执行环境,它被认为是window对象。因此所有全局变量和函数都是作为window对象的属性和方法创建的。某个执行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁(全局执行环境直到应用程序退出--例如关闭网页或浏览器时才会被销毁)
当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链的用途是保证对执行环境有权访问的所有变量和函数的有序访问。
如:
var color="blue";
function changeColor(){
var anotherColor="red";
function swapColor(){
var tempColor=anotherColor;
anotherColor=color;
color=tempColor;
}
}
它们的关系可用下图表示
对于例子中的swapColor而言,其作用域中包含3个对象:swapColor()的变量对象,changeColor()的变量对象和全局变量对象。swapColor的局部环境开始时会先在自己的变量对象中搜索变量和函数名,搜不到就再搜索上一级作用域链。但上级的作用域链不能搜索下级的作用域链。
2.1延长作用域链
当执行流进入下列任何一个语句时,作用域链就会得到加长:
①try-catch语句的catch块;
②with语句。
这两个语句都会在作用域链的前端添加一个变量对象。对with语句来说,其变量对象中包含着指定对象的所有属性和方法所作的变量声明,对catch语句来说,其变量对象中包含的是被抛出的错误对象的声明。这些对象都是只读的,因此在with和catch语句中声明的比那辆都会被添加到所在执行换将的变量对象中。(没用到过)
2.2没有块级作用域
在if语句中:
if(true){
var color="blue";
}
alert(color);//"blue"
可以看到color变量是在if语句中定义的,在c、c++或java中,color会在if执行完毕后被销毁。不过在javascript中,if语句中的变量声明会将变量添加到当前的执行环境(在这里是全局环境)中,for语句也有这一差异。
2.2.1声明变量
在使用var关键字声明变量时,这个变量将自动添加到距离最近的可用环境中。看个例子:
注:不建议不声明就直接初始化变量
2.2.2查询标识符
2.3垃圾收集
2.3.1标记清除
javascript中最常用的垃圾收集方式是标记清除。当变量进入环境(如在函数中声明一个变量)时,就将这个变量标记为”进入环境“,而当变量离开环境时,则将其标记为”离开环境“。可以使用任何方式来标记变流量。如可以通过翻转某个特殊的位来记录一个变量何时进入环境,或者使用一个”进入环境“的变量列表及一个”离开环境“的变量列表来跟踪哪个变量发生了变化。
2.3.2引用计数
另一种不太常见的垃圾收集策略叫引用计数。引用计数的含义是跟踪记录每个值被引用的次数。
2.3.3性能问题(不太懂)
2.3.4管理内存(貌似就是将一个值的引用赋值为null,手工解除某个对象的引用,这并不意味着自动回收该值所占用的内存,解除引用的真正作用是让值脱离执行环境,以便垃圾收集器下次运行时将其回收)