变量、作用域和内存问题

一、基本类型和引用类型的值

1、ECMAscript变量包含两种数据类型的值:基本类型值和引用类型值。

1)基本类型值:undefined、null、boolean、string和number

存储方式:在内存中占据大小固定的空间,被保存在栈内存中。

2)引用类型值:保存在内存中的对象

存储方式:堆内存

 

2、如何检测变量类型

1)typeof

传统的检验工具,但,typeof对于基本数据类型值中的undefined、boolean、string和number有效,但在检验null和对象时无效,检验结果二者均为object。

2)instanceof

判断一个对象是什么类型的对象,如果变量是给定引用类型的实例,instanceof操作符就会返回true。

语法如下:

result=rariable instanceof constructor

注意:instanceof不能用来检测基本数据类型,该操作符始终会返回false,因为基本数据类型根本不是对象

3)、传递参数

ECMAscript中所有函数的参数都是按值传递的。

易错点

•  向参数传递引用类型值时,会将这个值在内存中的地址复制给一个局部变量(参数实际上是这个函数的局部变量)。因此这个局部变量的变化会反映在函数的外部。

•  错误观点:在局部作用域中修改的对象会在全局作用域中反映出来,就说明参数是按引用传递的。证明如下

1 function setName(obj){
2    obj.name='xiaohuyang';
3    obj=new object();
4    obj.name='laohuyang';
5 }
6 var person=new object();
7 setName(person);
8 alert(person.name);//xiaohuyang

如果参数是按引用传递的,在函数内修改参数的值时,原始引用应同时变化,而事实并没有。事实上,当在函数内部重写obj时,这个变量引用的就是一个局部对象了,而这个局部对象在函数执行完毕后立即被销毁。(可以被ECMAscript函数的参数想象成局部变量~~~)

 

二、执行环境及作用域

这一块需要特别记得不多,主要是延长作用域链这一块。虽然执行环境的类型总共只有两种,全局和局部(函数),但还是有其他办法来延长作用域链的,这么说是因为有些语句可以在作用域的前端临时增加一个变量对象,该变量对象会在代码执行后被移除。在以下两种语句中会发生延长作用域链的情况。具体来说,是当执行流进入下列任何一个语句时,作用域链就会得到延长。

1、try-catch中的catch语句

对于catch语句来说,会创建一个新的变量对象,其中包含的是被抛出的错误对象的声明,而这个变量对象会被添加到作用域链的前端。(说实话这个我不会用哦,等我会用了再来补充~~~)

2、with语句

function buildUrl(){
  var qs='12345';
  with(location){
  var url=href+qs;
  }
  return url;
}

 

 with语句接受的location对象,其变量对象中就包含了location对象的所有属性和方法,而这个变量对象被添加到了作用域的前端。

 注意:js没有块级作用域哦。

 

三、垃圾收集

1、标记清除和引用计数

js具有自动垃圾收集机制,也就说执行环境会负责管理代码执行过程中使用的内存,其原理:找出不再继续使用的变量,然后释放其占用的内存。为此,垃圾收集器会按照固定的时间间隔周期性的执行这一操作。

那么,垃圾收集器如何判断垃圾变量是否还有存在的必要呢?垃圾收集器会跟踪变量,然后对不再有用的变量打上标记,以便将来收集回收的其占用的内存,用于标识无用变量的策略,具体到浏览器的实现,一般分为两种:

1)、标记清除——最常用(IE、Firefox、Opera、Chrome、Safari等)

当变量进入环境时,就把这个变量标记为“进入环境”,永远不能释放有进入环境标记变量的内存,因为只要执行流进入相应的环境,就可能会用到它们。而当变量离开环境时,则将其标记为”离开环境“。垃圾收集器在运行过程中会给存储在内存中的所有变量都加上标记,然后它会去掉环境中的变量及被环境中的变量引用的变量。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是,环境中的变量已经无法访问到这些变量了。最后,垃圾清理器完成内存清理工作,销毁带标记的值,并回收他们所占用的内存空间。

注意:不同浏览器使用的垃圾回收的时间间隔互有不同。

2)、引用计数——不太常见

引用计数,即跟踪记录每个值被引用的次数,声明了一个变量并将一个引用类型值赋给该变量时,则这个值得引用次数就是1(eg,var object1=new object()),如果同一个值每被引用一次,该值得引用标记就加1,包含对这个值引用的变量若取得其他值,该值标记就减一,当该值的引用标记为0时说明无法访问该值了,就可以将其占用的内存空间回收回来。最后,垃圾收集器定时清理。

注意:引用计数策略在遇到循环引用情况,会出现很大问题

 

2、性能问题

这一点不是很懂~~~

 

3、管理内存

由于分配给web浏览器的可用内存数量通常要比分配给桌面应用程序的少(出于安全方面考虑,防止运行js的网页耗尽全部系统内存而导致系统崩溃),这一内存限制问题 不仅会影响给变量分配内存,还会影响调用栈以及在 一个线程中能够同时执行的语句数量。

因此,确保占用最少的内存可以让页面获得更好的性能。而优化内存的最佳方式,就是为执行中的代码只保存必要的数据。一旦数据不再有用,最好将其设置为null来释放其引用——即,解除引用。这一做法适应大多数全局变量和全局对象的属性。局部变量会在他们执行环境时自动解除引用,其他的则需手动解除引用。

1 function createPerson(name){
2         var localPerson=new Object();
3         localPerson.name=name;
4         return localPerson;
5     }
6 var globalPerson=createPerson("xiaohuyang");
7 //下面必须手动解除localPerson的引用。
8 localPerson=null;

 

posted @ 2019-02-28 10:50  会开花的小胡杨  阅读(153)  评论(0编辑  收藏  举报