js笔记四:变量、作用域和内存问题

  Javascript的变量与其他语言的变量有很大的区别。Javascript变量松散类型的本质,决定了它只是在特定时间用于保存特定值的一个名字而已。由于不存在定义某个变量必须要保存任何数据类型的规则,变量的值以及其数据类型可以脚本的生命周期改变。

1、变量分为基本类型和引用类型

  Javascript变量可能包含两种不同数据类型的值,分别是基本类型和引用类型,基本类型是指那么保存在zhai内存的简单数据段,这种值完全保存在内存中的一个位置。

  基本类型分别是:undefined、Null、Boolen、Number、String这五种基本类型的值在内存中分别占有固定大小的空间,因此可以把他们的值保存在zhai内存中,这样也可以提高查询变量的速度,对于保存基本类型的值的变量,我们说它们是按值访问的,因为我们操作的是它们实际的保存的值

  而引用类型则是指对象那么保存在堆内存中的对象,意思是变量中保存的实际上只是一个指针,这个指针指向内存中的另一个位置,该位置保存对象

  如果赋值给变量的是一个引用类型的值,则必须在堆内存中为这个值分配空间,由于这种值得大小不固定,因此不能把他们保存在zhai内存中,但内存大小是固定的,因此可以将内存的地址保存在zhai内存中,这样当查询引用变量值得时候,就可以先从zhai中读取内存地址,然后在顺藤摸瓜地找到保存在堆内存中的值

2、复制变量值

  除了保存方式不同,从一个变量向另一个变量复制基本类型值和引用型值时也会存在不同

  如果从一个变量向另一个变量复制基本类型时、会在zhai中创建一个新值,然后把该值复制到为新的变量分配的位置上、

  如果从一个变量向另一个变量复制引用类型时、同样也会将存储在zhai中的值复制一分放到新变量分配的空间中,不同的是这个值得副本实际上是一个指针,而这个指针指向存储在堆中的一个对象,复制结束后、两个变量实际上将引用同一个对象。因此改变其中一个变量,就会影响另一个变量

3、传递参数

  Javascript中所有函数的参数都是按值传递的,也就是说,把函数外部的值复制给函数内部的参数,就是把值从一个变量复制到另一个变量一样。基本类型的值传递如同基本类型变量复制一样,引用类型复制如同引用类型一样。

  基本类型例子:

 function addTen(num){
   num += 10;
    return num;
 }
 var count = 20;
 var result = addTen(count);
 alert(count);         //20
 alert (result)         //30

  AddTen参数的num,实际上是一个局部变量,在函数内存num的值被加上了10,但这一变化并不会影响外部的count,因为参数num和count互相不认识,他们仅仅是具有相同的值。

      引用类型例子:

  function setName(obj){
    Obj.name = 'java';
 }
 var person = new object();
 setName(person);
 alert(person.name)      //java

  在这个函数内部,obj和person引用了同一个对象,换句话说,即使这个对象是按值传递的,obj也会按引用来访问同一个对象,于是在函数内部obj添加name属性后,外部的person也有所反应,因为person指向对象的在堆内存中只有一个,而且是全局对象。

  实际上在函数内部重写obj时,这个变量引用的就是一个新的对象了,而这个局部对象会在函数执行完后就立即被销毁。

  可以把javascript函数的参数想象成局部变量

 4、执行环境及作用域

  执行环境定义了变量或函数有权访问其他的数据,决定了他们各自的行为,每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。

  在WEB浏览器中,全局执行环境被认为是window对象,因此所有的全局变量和函数都是作为window对象的属性和方法创建的,某个执行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁,全局执行环境知道应用程序退出,例如关闭网页或浏览器时才会被销毁。

  每个函数在调用时都会创建自己的执行环境,当代码在一个执行环境中执行时,会创建有变量对象构成的一个作用域。作用域的用途,是保证对执行环境有权访问所有变量和函数的有序访问。作用域的前端,始终都是当前执行代码所在环境的变量对象。

  var color = "blue";
  function changeColor(){
       var anotherColor = "red";
       function swapColors(){
         var tempColor = anotherColor;
         anotherColor = color;
         color = temoColor;
         //这里可以访问color、anotherColor和tempColor;
    }
    //这里可以访问color和anotherColor,但不能访问tempColor
    Swapcolors();
  }
  changeColor();
  //这里不能访问anotherColor和tempColor,但可以访问color

  这个例子总swapColor()而言,其作用域链中包含3个对象:swapColor()的变量对象,changColor()的变量对象和全局变量对象。swapColor()的局部环境开始会先在自己的变量对象中搜索变量和函数名,如果搜索不到则一级一级的向上搜索。

  在这个搜索过程中如果存在一个局部的变量定义,则搜索会自动停止,不在进入另一个变量对象,换句话说,如果局部环境中存在着同名标示符,就不会使用位于父环境中的标示符了。

  变量的查询也不是没有代价的。很明显,访问局部变量要比访问全局变量更快,因为不用向上搜索作用域。

  这些环境之间的联系是线性的、有次序性的。每个环境都可以向上搜索作用域,以查询变量和函数名,但任何环境都不能通过向下搜索作用域链而进入另一个执行环境

5、垃圾收集

  垃圾收集机制原理:找出那么不再继续使用的变量,然后释放其       占用的内存。为此,垃圾收集器会按照固定的时间间隔(或代码中执行中预定的收集时间),周期性的执行这一个操作。

  分析函数中的局部变量声明周期。局部变量只在函数执行过程中存在。而这个过程中,会为局部变量的在zhai(堆)内存上分配相应的空间,以便存储他们的值,直至函数执行结束,此时,局部变量就没有存在的必要了,因此可以释放它们的内存。

  确保占最少的内存可以让页面获得更好的性能,而优化内存占用的最佳方式,就是执行中的代码只保存必要的数据。如果数据不用,最好通过复制为null来释放其引用、意味着切断变量与它此前引用值得链接。

原文地址:https://www.cnblogs.com/toxiaonan/p/2432553.html