JavaScript-变量、作用域、内存 小抄

来源:互联网 发布:mac能用ppt吗 编辑:程序博客网 时间:2024/05/17 01:08
JavaScript松散类型的本质决定了它 变量的值和数据类型可以在脚本的生命周期里改变。 这一特性有趣又强大,同时又是容易出问题的特性。但JavaScript的变量实际复杂程度远不止如此。
变量
ECMAScript变量包含两种不同数据类型的值:基本数据类型和引用数据类型。基本的5种类型是按值访问的,引用类型是保存在内存中的对象。
JavaScript不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间,在操作对象时实际上操作的是对象的引用而不是实际的对象。引用类型的属性可以动态的调整,可以添加也可以改变和删除其属性和方法。
变量复制
变量的复制也存在不同,基本类型复制后会成为两个独立的变量;引用类型变量的复制其实只是复制了变量的指针,两个变量将引用同一个对象,因此改变一个变量,会影响到另外的一个变量。
var obj1 = new Object();
var obj2 = obj1;
obj2.name = "nicholas";
alert(obj1.name);// nicholas
传递参数
ECMAScript的所有函数的参数都是按值传递的,就是说把函数外部的值复制给函数内部就像把值从一个变量复制到另一个变量一样。  基本类型的传递就像基本类型复制一样; 引用类型的传递就像引用类型的复制一样。




检测类型
基本的数据类型用typeof检测最得力,它能够返回来变量是数字、字符串、布尔值、还是undefined;但是对于对象或者null, typeof只能返回"object";
在检测引用类型的值时,我们想知道的是引用的值时什么类型的对象,ECMAScript提供了instanceof操作符,用法:
result = variable instanceof constructor;
如果变量是给定引用类型的实例,那么instanceof操作符就会返回true;
alert(person instanceof Object);//所有的引用类型的值都是Object的实例,因此在检测引用类型的值和Object构造函数时instanceof返回的始终是true;
alert(person instanceof RegExp);
alert(person instanceof Array);


执行环境及作用域
执行环境定义了变量或函数有权访问的其他数据,决定了他们各自的行为。 每个执行环境都有个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。 虽然我们编写代码的时候没有办法访问它,但是解析器在处理数据的时候会使用它。
全局执行环境是最外围的执行环境,web浏览器中全局执行环境被认为是window对象,因此所有的全局变量 和函数都是作为window的属性和方法创建的。


每个函数都有自己的执行环境,当执行流进入一个函数时,函数的环境都会被推入一个环境栈中,当函数执行之后,栈将其环境弹出,把控制权返还给之前的执行环境。
当代码在一个环境中执行时,会创建变量对象的一个作用域链,作用域链的作用是保证执行环境有权访问的所有变量和函数有序访问。作用域链的最前端始终是当前执行代码所在的环境变量对象。作用域链始终是一级一级的包含关系,一直延续到全局执行环境。
标识符解析 是沿着作用域链一级一级的搜索标识符的过程。




函数的作用域链包含两个对象,自己的变量对象和全局环境中的变量对象, 可以在函数内部访问变量color是因为在作用域链中可以找到他。


内部的环境可以通过作用域链访问所有外部环境,但是外部的环境不能访问内部环境的任何变量和函数。  每个环境都可以向上搜索所用域链,查询函数和变量名。任何环境都不能通过向下搜索作用域链而进入另一个执行环境。


延长作用域链
执行到try catch 语句的catch块;
with语句时作用域链就会得到加长:这两个语句会在作用域链的前端添加一个变量对象。
没有块级作用域
会JavaScript不想C语言一样用花括号来标注块级作用域,C语言中花括弧中间声明的变量在执行完毕之后会销毁,但是JavaScript并不会,它会将声明的变量添加到当前的执行环境;
在变量声明时,使用var声明的变量会被自动添加到最近的环境中,如果初始化没有使用var声明,则该变量会被添加到全局环境。
查询标识符:
当某个环境中引入新的标识符时,必须通过搜索来确定标识符代表什么,搜索的过程从作用域链的前端开始,向上逐级查询与给定标识符匹配的,如果在局部环境中找到了,则会停止搜索;如果没有找到,则会继续沿作用域链向上搜索,搜索过程一直会追溯到全局环境的变量对象,如果全局环境变量对象中都没有找到则说明该变量没有声明。


如果局部环境中存在同名的标识符,则不会使用父环境中的标识符。
变量查询也不是没有代价的,很明显访问局部变量要比访问全局变量快,因为不用向上搜索作用域链,但是JavaScript在引擎优化标识符查询方面做得不错,这个差异恐怕将来要忽略不计了。


垃圾回收机制
JavaScript有自动垃圾回收机制,也就是说执行环境会负责管理代码执行过程中使用的内存。
标记清除,JavaScript常用的垃圾回收方式是标记清除,IE FireFox Opera Chrome Safari 的JavaScript使用的都是标记清除的垃圾回收方式,只不过垃圾回收的间隔不同。
引用计数 这是一种不太常见的垃圾回收策略,它记录每个值被引用的次数。
但是这种引用会出现循环引用的问题,导致变量占的内存空间永远不会被释放。
function problem(){
var obj1 = new Object();
var obj2 = new Object();
obj1.someObj = obj2;
obj2.someOtherObj = obj1;
}
出现这样的问题时候,两个obj的计数器都是2,为了避免这样的问题,当不使用的时候手工断开手工将变量置空。
性能问题,垃圾回收器是周期进行的,如果为变量分配的内存数量很可观,那回收工作量也是相当大的,所以垃圾回收的时间间隔是非常重要的问题。


管理内存 出于安全方面的考虑,分配给web浏览器的内存数量通常比桌面应用程序少,为了确保占用少的内存页面可以获得更好的性能,优化内存的最佳方式是执行的代码中值保存必要的数据,一旦数据不再使用最好将其值设置成为null,来释放其引用。--这个方式叫做 解除引用。解除引用的真正作用是让其值脱离执行环境,正真的解除在垃圾回收器下次运行的时候将其回收。


小结:
javascript变量可以用来保存两种类型的值,基本类型和引用类型的值。 基本类型的值有 undefined null boolean number string;
基本类型的值在内存中占有固定大小的空间,因此被保存在栈内存中;
从一个变量向另一个变量复制基本类型的值,会创建这个值的一个副本。
引用类型的值是对象,保存在堆中内存中。
从一个变量向另一个变量复制引用类型的值,复制的其实是指针,因此两个变量最终会指向同一个对象。
执行环境有函数执行环境和全局执行环境之分
每一次进入一个新的全局环境都会创建一个用于搜索变量和函数的作用域链;
变量的执行环境有助于确定该何时释放内存。




0 0