javascript高级程序设计(变量、作用域和内存问题)

4.1基本类型和引用类型
ECMAScript变量可能包含两种不同数据类型的值:基本类型和引用类型。基本类型是指简单的数据段,引用类型是指那些可能由多个值构成的对象。

第三章讨论了5种基本数据类型:undefined,null,boolean,number,string.这五中基本数据类型是按值访问的,因为可以操作保存在变量种的实际的值。

引用类型的值是保存在内存中的对象。与其他语言不同,JavaScript不允许直接操作对象的内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。为此,引用类型的值是按被引用访问的。

4.1.1 动态的属性
定义:定义基本类型值和引用类型值的方式是类似的:创建一个变量并为该变量赋值。但是,当这个值保存在变量中后,对不同类型可以执行的操作则大相径庭。

对于引用类型的值,我们可以为其添加属性和方法,也可以改变和删除其属性和方法。

var person=new Object();
person.name="Nicholas";
alert(person.name);//Nicholas

对象可以添加属性name,并将字符串赋值给这个属性。只要对象不被删除或者这个属性不被删除,这个属性会一直存在。
但是我们不能给基本类型的值添加属性,尽管这样做不会导致任何错误。

var name="Nicholas";
name.age=27;
alert(name.age);//undefined

//感觉引用类型就是对象类型啊

4.1.2复制变量值

var num1=5;
var num2=num1;

除了保存方式不同之外,在从一个变量向另一个变量赋值基本类型值和引用类型值时,也存在不同。如果从一个变量向另一个变量赋值基本类型的值,会在变量对象上创建一个新值,然后把该值复制到为新变量分配的位置上。

因此这两个变量可以参与任何操作而不会相互影响。

这里写图片描述

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

    var obj1= new Object();
    var onj2=obj1;
    obj1.name="Nicholas";
    alert("obj2.name");//"Nicholas"

这里写图片描述

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

有不少开发人员会困惑,访问变量有按值和按引用两种方式,而参数只能按值传递。

在向参数传递基本类型的值时,被传递的值会被复制给一个局部变量(即命名参数,或者用ECMAScript的概念来说就是arguments对象中的一个元素)。在向参数传递引用类型的值时,会把这个值在内存中的地址复制给一个局部变量,因此这个局部变量的变化会反映在函数的外部。

function addTen(num){
    num+=10;
    return num;
}
var count=20;
var result=addTen(count);
alert(count);//20,没有变化
alert(result);//30

作用域:http://www.cnblogs.com/hfxm/p/5547922.html
局部变量声明被提前:http://www.cnblogs.com/hfxm/p/5550283.html

4.2执行环境以及作用域
全局执行环境是最外围的一个执行环境,根据ECMAscript实现所在的宿主环境不同,表示执行环境的对象也不一样。在WEB浏览器中,全局执行环境被认为是window对象,因此所有的全局变量和函数都是作为window对象的属性和方法创建的。某个执行环境中的所有代码执行完毕后,该环境被销毁。保存在其中的所有变量和函数定义也随之销毁。

当代码在一个环境中执行,会创建变量对象的一个作用域链。

作用链的用途是保证对执行环境有权访问的所有变量和函数的有序访问。作用域链的前端,始终都是当前执行代码所在环境的变量对象。

如果这个环境是函数,则将其活动对象作为变量对象。活动对象在最开始时只包含一个变量,即arguments对象。

其中内部环境可以通过作用域链访问所有的外部环境。但外部环境不能访问内部环境中的任何变量和函数。

4.2.1延长作用域
try-catch中的catch
with语句

function buildUl(){
    var qs="?debug=true";
    with(location){
      var url=href+qs;
    }
    return url;
  }

with语句接收的是location对象,因此其变量对象中就包含了Location对象的属性和方法。而这个变量对象被添加到了作用域得到前端。bindUrl()函数定义了一个变量qs。当在with语句中引用变量href时(实际上是引用location.href),可以在当前执行环境的变量对象中找到。当引用变量qs时,引用的则是在buildUrl()中定义的那个变量,而该变量则位于函数环境的变量对象中。至于with内部,则定义了一个名为url的 变量。因此url就成了函数执行环境的一部分,可以作为函数的值被返回。

4.2.2 没有块级作用域

if(true){
    var color="blue";
  }
  alert(color);//blue

如果在if语句中定义变量color,如果在java语句中将被销毁。但是在javascript中,if将会将变量添加到当前的执行环境。

for(var i=0;i<10;i++){
    doSome(i);
  }
  alert(i);//10

对于JavaScript来说,由for语句创建的变量i即使在for循环结束后,也依旧会存在于循环外部的执行环境中。

1.声明变量
使用var声明的变量会自动被添加到最接近的 环境中。在函数内部,最接近的环境就是函数的局部环境;
在with语句中,最接近的环境就是函数环境。
如果初始化变量时没有使用var声明,该变量会自动被添加到全局环境中。

2.查询return标识符(这里的局部和全局并不是指变量而是指环境)
查询标识符时,如果在局部环境中搜索到了该标识符,搜索过程停止,变量就绪。如果在局部环境中没有找到该变量名,则继续沿着作用链向上搜索。

var color="blue";
  function getColor(){
    return color;
  }
  alert(getColor());//"blue"

在搜索过程中,如果存在一个局部的变量的定义,则搜索会自动停止,不再进入另一个变量对象。

var color="blue";
  function getColor(){
    var color="red";
    return color;
  }
  alert(getColor());//"red"

4.3垃圾收集
javascript具有自动垃圾收集机制:找出那些不再继续使用的变量,然后释放其占有内存。但是具体到浏览器中的实现,则通常有两个策略:

4.3.1标记清除
垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记。然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记。而在此后被加上标记的变量江北视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后垃圾收集器完成内存清除工作。

4.3.2引用计数

typeof与instanceof:
https://www.ibm.com/developerworks/cn/web/1306_jiangjj_jsinstanceof/

这里写图片描述

这里写图片描述

阅读更多

没有更多推荐了,返回首页