变量作用域及内存
Javascript的变量与其他语言的变量有很大区别,Javascript变量是松散型的(不强制类型),决定它只是在特定时间用于保存特定值得一个名字而已
。由于不存在定义某变量必须要保存何种数据类型值的规则,变量的值及其数据类型可以在脚本的生命周期内改变。
变量及作用域
基本类型和引用类型的值
变量可能包含两种不同的数据类型的值,基本类型和引用类型值,基本类型值指的那些保存在栈内存中的数据段,即这种完全保存在内存中的一个位置,
儿引用类型值则是指那些保存在堆内存中的对象,意义是变量中保存的实际上是一个指针,这个指针指向内存中的另一个位置,该位置保存对象。
将一个值赋给变量时,解析器必须确定这个值是基本类型值,还是引用类型值,基本类型值有一下几种(string Undefined Null Boolean和 Number)。
这些类型在内存中分别占有固定大小的空间,我们通过安值来访问的。
PS:在某些语言中,字符串以对象形式来表示,一次被认为是引用类型,ECMAJavascript放弃这一传统。
如果赋值的是引用类型的值,则必须在堆内存中为这个值分配空间,由于这个值大小不固定,因此不能把他们保存到栈内存中,但内存地址大小是固定的,
因此可以将内存地址保存在栈内存中,这样,当查询引用类型的变量时,先从栈中读取内存地址,然后在通过地址到堆中查找,对于这种,我们把它叫做按引用
访问。
var box=new Object(); //创建一个box对象 box.name='杜威'; //添加一个name属性 alert(box.name); //返回杜威 var box="lee"; //创建一个基本类型变量box box.name="zhongguo"; //为box添加属性很怪异 alert(box.name); //返回Undefined 找不到 出错 ps 不是引用类型无法输出
复制变量的值:
在变量复制方面,基本类型和引用类型有所不同,基本类型复制的是值的本身,而引用类型复制的是地址。
var box=new Object(); box.name="杜威"; var box2=box; // box.name="zhongguo"; //当我们box.name重新赋值的时候box2.name也会改变因为他们都指向同一个Object中的name alert(box.name); alert(box2.name);
var box="Lee"; var box2=box; // box="fus"; 当我在改变box的值的时候,box2的值不会改变 alert(box); alert(box2);
传递参数:
Javascrip中所有函数的参数都是按值传递的,言下之意就是说,参数不能按引用传递。虽然变量有基本类型和引用类型之分。
function box(num){ num+=10; return num; } var num=50; alert(box(num)); alert(num); // ps:以上的代码中,传递的参数是一个基本类型的值,而函数里面的num是一个局部变量和外面的nnum // 没有任何关系
function box(obj){ //这里将要传递一个引用类型参数,但不能按引用传递是按值传递的 obj.name="Lee"; //JS没有按引用传递的功能,切记,不能把传递引用参数理解成按引用传递 } var obj={}; box(obj); alert(obj.name);
虽然typeof运算符在检查基本数据类型的时候非常好用,但检测引用引用类型的时候,它就不是那么好用了,通常,我们并不想知道它是不是对象,而是想知道它到底
是什么类型的对象。因为数组也是object,null也是object等等。
使用typeof
var box=[1,2,3]; alert(typeof box); var box2={}; alert(typeof box2); var box3=/g/; alert(typeof box3);
使用instanceof(不能检查基本类型)
var box=[1,2,3]; alert(box instanceof Array); var box2={}; alert(box2 instanceof Object); var box3=/g/; alert(box3 instanceof RegExp);
执行环境与作用域
执行还加精是Javascript中最为重要的一个概念,执行环境定义了变量或函数有权访问其他数据,决定了它们各自行为
全局执行环境是最外围的执行换进个,在web浏览器中,全局执行环境被认为是window对象,因此所有的全局变量和函数都是作为window
对象的属性和方法创建的。
var box="blue"; function setbox(){ return 123; } alert(box); alert(setbox()); // alert(window.box); 返回blue 说明box和setbox是window下的属性和方法 // alert(window.setbox());
var box="Lee"; function setColor(){ var box="KKK"; return box; //这个是局部变量,他的范围在setColor()里,出来就不认识了 } setColor(); alert(box);
var box="Lee"; function setBox(box){ //通过传参,也是局部变量,作用于在setBox范围下 alert(box); } setBox("red"); alert(box);
var box="Lee"; function setBox(){ function setColor(){ //setColor方法作用域在setBox()里 var b="KKK"; //b的作用域在setColor()里 alert(b); return 123; } return setColor(); } alert(setBox());
作用域链
每个函数被调用时都会创建自己的执行环境,当执行到这个函数时,函数的环境就会被推到环境栈中去执行 ,而执行后又在环境栈中退出,把控制权交给上一级
执行环境。
当代码在一个环境中执行时,就会形成一个种作用域链的东西,它的用途时保证对执行环境中又访问权限的变量和函数进行有序访问,作用域链的前缀,就时执行
环境的变量对象。
没有块级作用域
块级作用域表示诸如if语句等由花括号封闭的代码块,所以,支持条件判断定义变量
if (true) { var box="lee"; //if语句是没有封闭作用域的 } alert(box); alert(window.box); //box同样也是window下的属性
for (var i = 0; i <= 10; i++) { //for循环同样也不封闭作用域 var box="lee"; } alert(i); //i box 都是window下的属性 alert(box);
变量搜索
var box="Lee"; function setBox(){ var box="blue"; //当作用域由box,优先使用,没有的话就会向上搜索 return box; } alert(setBox()); //变量是向上搜索的