JavaScript学习 三、变量、作用域和内存

javascript的变量和C、java相去甚远,按照《画家与黑客》的说法,弱类型的变量是强大语言的基础;作用域与其他语言类似,但没有块级作用域;内存管理就要靠大学学的操作系统那门课的基础了;看来当时学的时候不知道有什么用,没准到哪天就豁然开朗了,所以知识储备还是必不可少的。

变量

ECMAScript变量包括两种类型:基本类型和引用类型

基本类型是指简单的数据段(Undefined、Null、Boolean、Number、String),引用类型是指那些可能由多个值构成的对象(Object)。

这两种类型的区别是:基本类型操作的是保存在变量中的实际的值,在传递参数或复制变量的时候,直接把变量值传递给参数。而引用类型的值是保存在内存中的对象,传递参数或复制变量时传递的是指针。

String类型在其他语言中一般被当做对象,而在Javascript中是基本类型。

ECMAScript中传递参数的时候要注意引用的传递,实际上是把指针的内容传递给参数。参数指针变化时,不影响原引用。参数操作指向的内容时,原引用同步变化。

function setName(obj){
    obj.name="JavaScript";
    obj = new Object();    //参数的内容发生变化
    obj.name="React";
    
}

var person=new Object();
setName(person);
console.log(person.name);  //返回JavaScript/

实际上Java语言也是如此处理的:

public class JavaArguments{

    public static void main(String[] args){
        StringBuffer temp = new StringBuffer();
        temp.append("hello");

        test(temp);
        System.out.println(temp.toString());  //返回java
    }

    public static void test(StringBuffer sb){
        sb.append(" java");
        sb=new StringBuffer();
        sb.append("new StringBuffer");
    }
}

变量类型的检测可以是用typeof操作符,但是对于引用类型,只能返回object字符串,如果想知道对象的类型,则需要instanceof操作符,正确则返回true,否则返回false。

console.log(person instanceof Object);
console.log(person instanceof Array);
console.log(person instanceof RegExp);

执行环境及作用域

 执行环境(execution context)是JavaScript中最为重要的一个概念。执行环境定义了变量或函数有权访问的其他数据,决定了他们各自的行为。每个执行环境都有一个与之关联的变量对象(variable object)。

全局执行环境是最外围的一个执行环境。根据宿主环境不同,表示执行环境的对象也不一样。在Web浏览器中,全局执行环境被认为是window对象,因此所有全局变量和函数都作为window对象的属性和方法创建的。

某个执行环境中所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁(全局执行环境知道应用程序退出--例如关闭网页或浏览器--时才被销毁)。

每一个函数都有自己的执行环境,当执行流进入一个函数时,函数的环境就会被推入一个环境栈中,而在环境执行后,栈将其环境弹出,把控制权返还给之前的执行环境。

当代码在环境中执行时,会创建变量对象的一个作用域链(scope chain)。自身所在环境的变量对象是链条的前端,末端始终是全局环境的变量对象。如果一直找不到标识符,则会发生错误。

var color="blue";
function changeColor(){
    var anotherColor = "red";

    function swapColors(){
        var tempColor = anotherColor;
        anotherColor = color;
        color = tempColor;
        console.log("--------- 1-----------------")
        console.log(color);               //red
        console.log(anotherColor);  //blue
        console.log(tempColor);      //red
    }

    swapColors();
    console.log("--------- 2-----------------")
    console.log(color);                     //red
    console.log(anotherColor);        //blue
    //console.log(tempColor);          //undefined错误
}


changeColor();
console.log("--------- 3-----------------")
console.log(color);                        //red
//console.log(anotherColor);         //undefined错误
//console.log(tempColor);             //undefined错误
作用域链

with语句实际上就是指定了作用域链的前端。

 JavaScript中没有块级作用域,所以for语句中声明的变量,在块的外部一样能够访问。

垃圾回收

 JavaScript具有自动垃圾回收机制

针对局部变量,局部变量只在函数执行的过程中存在,在栈(或堆)的顶部分配相应的空间,存储它们的值,函数执行结束后,变量也就没用了,此时即可释放内存。

判断变量是否有用的策略可能会因实现而异。

具体到浏览器,通常采用标记清除(mark-and-sweep)策略。

垃圾收集器在运行时会给存储在内存中的所有变量都加上标记,然后他会去掉环境中的变量以及被环境的变量引用的变量的标记。至此仍然有标记的变量将被视为准备删除的变量,因为环境中的变量已经无法访问到这些变量了。最后垃圾收集器完成内存清除工作。销毁那些带标志的值并回收他们所占用的内存空间。

作为开发人员,我们能够做的,是在全局变量和全局对象不再使用后,将其值设置位null来释放引用。这个做法叫做 解除引用(dereferencing)。

小结

 JavaScript变量可以用来保存两种类型的值:基本类型值(Undefined、Null、Boolean、Number和String)和引用类型值。特点如下:

  • 基本类型值在内存中占据固定大小的空间,因此被保存在栈空间中。
  • 从一个变量向另一个变脸复制基本类型的值,会创建这个值的副本。
  • 引用类型的值是对象,保存在堆内存中。
  • 包含引用类型值的变量实际上包含的并不是对象本身,而是指向该对象的指针。
  • 从一个变量向另一个变量复制引用类型的值,复制的其实是指针,因此两个变量最终都指向同一个对象。
  • 可以用typeof来判断一个值哪种基本类型,而确定一个值是哪种引用类型可以使用instanceof操作符。

关于执行环境:

  • 执行环境有全局执行环境和函数执行环境之分。
  • 每次进入一个新的执行环境,都会创建一会用于搜索变量和函数的作用域链。
  • 函数的局部环境不仅有全访问函数作用域中的变量,而且有圈访问其包含环境,乃至全局环境。
  • 全局环境只能访问在全局环境中定义的变量和函数,而不能直接访问局部环境中的任何数据。
  • 变量的执行环境有助于确定应该何时释放内存。

关于内存管理:

  • 离开作用域的值将被标记位可回收,因此将在垃圾收集期间被删除。
  • “标记清除”是目前主流的垃圾收集算法,这种算法的思想是给当前不使用的值加上标记,然后再回收其内存。
  • 接触变量的引用不仅有助于消除循环引用现象,而且对垃圾收集也有好处。为了确保有效地回收内存,应该及时解除不再使用的全局对象、全局对象属性以及循环引用变量的引用。

变量

变量

原文地址:https://www.cnblogs.com/liangflying521/p/5088174.html