4.1 什么是变量?
变量是一个和数值相关的名字。我们经常说,变量“包含”或者“存储”了一个值。有了变量,在程序中就可以存储和操作数据了。所以说,变量就是一个用于存储数值的一个名字。
4.2 变量的类型:
Javascript是非类型(untype)值的,这就以为着javascript变量可以存放任意类型的的值。因为缺少类型规则,javascript可以快速的将一种类型的值转换成另一种类型的值。例如你想做这样的定义,var string = "s"+10,10是数字,这时候javascript就降10转化为字符串10连接在s后面,结果string = "s10"。相比之下,c,C++是强类型语言,c,c++的变量只能存放它声明了的特定类型的变量。
4.3 变量的声明
在javascript程序中使用变量之前,必须先声明。变量使用关键字 var 声明,例如,var i; var m;
也可以使用一个var 关键字声明多个变量 var i,m;
还可以在将变量声明和初始化绑定在一起 var i = 10; var string = "message";
如果一个变量声明,但是并没有初始化。虽然这个变量声明了,但是在给它存入一个值之前,它的初始值为“undefined”;
由于var声明的变量是永久性的,用delete运算符来删除这些变量将会引发错误。
重复的声明和遗漏的声明
使用var多次声明同一变量是合法的。单如果想读取一个未声明变量的值,javascript会生成一个错误。如果尝试给一个未声明的变量赋值,javascript会隐式声明该变量。但是隐式声明的变量为全局变量,即使是只是在一个函数内使用。
4.4 变量的作用域
变量的作用域,通俗讲就是变量的在哪个区域内起作用。全局作用域是全局的,即在javascript代码中处处都有定义。局部作用域,只在局部有效。在函数内部声明的变量和函数的参数,就只在函数体内有定义,它们是局部变量。
在函数体内,局部变量优先级比同名的全局变量优先级高。如果给一个局部变量或参数声明的名字和全局变量相同,那么久有效的隐藏了这个全局变量。
例如
var scope = "global"; function checkscope(){ var scope = "local scope"; document.write(scope); } checkscope(); //输出 local scope;
在全局变量声明时,可以不使用关键词var,但是声明局部变量时,一定要加var,否则,他会改变全局变量的值。
<script type="text/javascript"> scope = "global"; //声明全局变量,没有使用关键字var function checkscope(){ scope = "local";//声明局部变量,没有使用关键字var,改变了全局变量的值 document.write(scope);//使用全局变量的值 myscope = "local";//声明一个新的全局变量 document.write(myscope); //使用新的全局变量 } checkscope();//输出 locallocal document.write(scope);//输出local </script>
4.4.1 没有块级作用域
什么是块级作用域:任何一对花括号({和})中的语句集都属于一个块,在这之中定义的所有变量在代码块外都是不可见的,我们称之为块级作用域。
函数作用域:定义在函数中的参数和变量在函数外部是不可见的。
c,c++拥有块级作用域
一个c语言的例子
void main(){ int i=2; i--; if(i){ int j=3; } printf("%d\n",j); }
结果为 “use an undefined variable:j”,因为c语言拥有块级作用域,j在if块中定义,块外无法访问
看一个js的例子
function test(){ for(var i=0;i<3;i++){} alert(i); } test();//结果i=3
换句话说i能够访问在for块中定义的i,就说明js没有块作用域,但只有函数作用域,即在函数任何部分定义的变量,在该函数中的任何地方都可以访问;
4.4.2
未定义的变量和未赋值的变量
未定义的变量:从未声明的变量;
为赋值的变量:声明过,但是没有初始化;
之间的区别
var i;//定义一个未赋值的变量,调用时为undefined alert(u);//定义一个未声明的变量,调用时会报错 u = 3; //给一个未声明的变量赋值来声明这个变量
4.5 基本类型和引用类型
但是字符串是一个特例,具有可变大小,但是我们希望javascript只是复制字符串的引用而不是他的内容。
4.6 垃圾收集
因为引用没有固定类型。javascript每次创建字符串,数组,解释器必须分配内存存储那个实体。javascript可以使用垃圾收集的方法去释放内存。javascript的解释器确定程序中的一个对象是无用的时候(程序中使用的变量再也无法引用这个对象了),即不需要这个对象,可以把它占用内存释放掉了
var s = "hello"; var u = s.toUpperCase(); s = u;
代码运行之后,就不能再获得原始的字符串“hello”,因为程序中没有变量再引用它。系统检测到这一事实后,就会释放该字符串的存储空间。
4.7
4.7 javascript预编译与运行期过程
javascript这种解释型语言,分为两个阶段:编译期(类似于预编译,一下统称为“预编译”)与运行期。
在预编译时期,javascript以函数来划分作用域,然后逐层为其以var声明的变量(建成,var变量)和函数定义开辟内存空间,然后为对var变量进行特殊处理,统统赋值为undefined。
运行期是在为var变量与函数定义分配空间后立即执行,并且是逐行往下执行的。
来看一个例子
<script type="text/javascript">
var a=100;
var b=true;
function test(){
alert(a);
alert(b);
b=false;
alert(b);
var a=200;
alert(a/2);
alert(++Math.PI);
alert(Math.PI++);
}
test();
</script>
在预编译以后变量的分布情况
javascript的运行期,在var变量和函数定义分布内存之后,立即执行,而且是一步一步执行。
第一行,它为外围作用域的a赋值100;
第一行,它为外围作用域的b赋值true;
第三行,进图test()作用域,简称内围作用域;
第四行,就立即调用内围作用域的a,这时它还没有来得及赋值呢!不过它已经声明过了,因此默认为其赋值为undefined(在预编译阶段,见图),于是alert为undefined
第五行就调用b时,发现test的作用域内没有b,就往外寻找,而b在第二行就赋值为true,于是alert为true。
第六行,为一个赋值操作,把外围的b变量改赋为false。于是到第7行时,alert为false。
作用域总结:变量会首先寻找内围作用域,内围作用域级别比外围高。