《高级程序设计》 4 变量、作用域和内存问题

  • 基本类型值和引用类型值
  • 执行环境及作用域
  • 垃圾收集

1、基本类型值和引用类型值

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

5种基本数据类型:(Undefined,Null,Boolean,Number,String)是按值访问的,因为可以操作保存在变量中的实际的值。

引用类型的值是保存在内存中的对象。javascript不能直接访问内存中的位置,也就是不能直接操作对象的内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。为此,引用类型的值是按引用访问的。

注:在很多语言中,字符串以对象的形式来表示,因此被认为是引用类型的。javascript放弃了这一传统。

1)动态的属性

我们可以为引用类型添加属性,并访问这个新属性,但是不能给基本类型的值添加属性。

var person=new Object();
person.name="Nicholas";
alert(person.name);  //"Nicholas"
//not
var name="Nicholas";
name.age=27;
alert(name.age); //undefined
//    只能给引用类型值动态地添加属性,以便将来使用

2)复制变量值

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

var num1 = 5;
var num2 = num1;
alert(num2);  //5
//    如果从一个变量向另一个变量复制基本类型的值,会在变量对象上创建一个新值,然后把该值复制到为新变量分配的位置上。
//    num2中的5与num1中的5是完全独立的。这两个变量可以参与任何操作而不会相互影响。
var obj1=new Object();
var obj2=obj1;
obj1.name="Nicholas";
alert(obj2.name);  //"Nicholas"
//    当一个变量向另一个变量复制引用类型的值时,同样也会将存储在变量对象中的值复制一份放到为新的变量分配的空间中。不同的是,这个值的副本
//    实际上是一个指针,而这个指针指向存储在堆中的一个对象。两个变量实际将引用同一个对象。因此,改变其中一个变量,就会影响另一个变量。

3)传递参数

javascript中所有函数的参数都是按值传递的。基本类型值的传递如同基本类型变量的复制一样,引用类型值的传递如同引用类型变量的复制一样。

在向参数传递基本类型的值时,被传递的值会被复制给一个局部变量(即命名参数,或者用javascript的概念来说,就是arguments对象中的一个元素)。

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

    //    基本类型
    function addTen(num) {
        num += 10;
        return num;
    }
    var count = 20;
    var result = addTen(count);
    alert(count); //20
    alert(result); //30
    //    引用类型
    function setName(obj) {
        obj.name = "Nicholas";
    }
    var person = new Object();
    person.name = "Greg";
    alert(person.name); //"Greg"
    setName(person);
    alert(person.name); //"Nicholas"
//    在函数内部,obj和person引用的是同一个对象。
//    很多开发人员错误的认为:在局部作用域中修改的对象会在全局作用域中反映出来,就说明参数是按引用传递的,
// 为了证明对象是按值传递的,对比:
    function setName1(obj){
        obj.name="Nicholas";
        obj=new Object();
        obj.name="Greg";
    }
    var person1=new Object();
    setName1(person1);
    alert(person1.name); //Nicholas
//    当在函数内部重写obj时,这个变量引用的就是一个局部对象了。而这个局部对象会在函数执行完毕后立即被销毁。

注意:可以把javascript函数的参数想象成局部变量。

4)检测类型

当要检测一个变量是不是基本数据类型时,使用typeof操作符是最佳的工具。

    //    typeof操作符
//    var s = "Nicholas";
//    var b = true;
//    var i = 22;
//    var u;
//    var n = null;
//    var o = new Object();
//    alert(typeof s); //string
//    alert(typeof b); //boolean
//    alert(typeof i); //number
//    alert(typeof u); //undefined
//    alert(typeof n); //object
//    alert(typeof o); //object
    //    当我们并不是想知道某个值是对象,而是想知道它是什么类型的对象。使用:
    //    instanceof 操作符
    var person = new Object();
    var array = new Array();
    var pattern = new RegExp();
    alert(person instanceof Object); //true
    alert(array instanceof Array); //true
    alert(array instanceof Object); //true .所有引用类型的值都是Object的实例,因此在检测一个引用类型值和Object构造函数时,
//    instanceof操作符始终会返还true
    alert(pattern instanceof RegExp); //true

使用typeof操作符检测函数时,该操作符会返回“function”。

在ie和firefox中,对正则表达式应用typeof会返回“object“

2、执行环境及作用域

执行环境定义了变量或函数有权访问的其他数据,决定了了它们各自的行为。

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

当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。作用域链的前端,始终都是当前执行的代码所在环境的变量对象。如果这个环境是函数,则将其活动对象作为变量的对象。活动对象在最开始只包含一个变量,即arguments对象(这个对象在全局环境中是不存在的)。作用域链中的下一个变量对象来自包含(外部)环境,而再下一个变量对象则来自下一个包含环境。这样,一直延续到全局执行环境;全局执行环境的变量对象始终都是作用域链中的最后一个对象。

标识符的解析是沿着作用域链一级一级地搜索标识符的过程。搜索过程始终从作用域链的前端开始,然后逐级地向后回溯,直到找到标识符为止(如果找不到标识符,通常会导致错误发生),示例:

//    var color = "blue";
//    function changeColor() {
//        if (color == "blue") {
//            color = "red";
//        } else {
//            color = "blue";
//        }
//    }
//    changeColor();
//    alert("Color is now " + color);  //"Color is now red"
//    函数changeColor()的作用域链包含链各个对象:它自己的变量对象(其中定义着arguments对象)和全局环境的变量对象。
// 可以在函数内部访问变量color,就是因为可以在这个作用域链中找到它。
//    此外,在局部作用域中定义的变量可以在局部环境中与全局变量互换使用,如下:
    var color="blue";
    function changeColor(){
        var anotherColor="red";
        function swapColors(){
            var tempColor=anotherColor;
            anotherColor=color;
            color=tempColor;
//            这里可以访问color,anotherColor,tempColor
        }
//        这里可以访问color和anotherColor,但不能访问tempColor
        swapColors();
        alert(anotherColor); //"blue"
    }
//    这里只能访问color
    changeColor();
    alert("Color is now "+color); //"Color is now red"

注意:函数参数也被当作变量来对待,因此其访问规则与其执行环境中的其它变量相同

3、垃圾收集

时间: 2024-08-27 14:23:23

《高级程序设计》 4 变量、作用域和内存问题的相关文章

第一百零六节,JavaScript变量作用域及内存

JavaScript变量作用域及内存 学习要点: 1.变量及作用域 2.内存问题 JavaScript的变量与其他语言的变量有很大区别.JavaScript变量是松散型的(不强制类型)本质,决定了它只是在特定时间用于保存特定值的一个名字而已.由于不存在定义某个变量必须要保存何种数据类型值的规则,变量的值及其数据类型可以在脚本的生命周期内改变. 一.变量及作用域 1.基本类型和引用类型的值 ECMAScript变量可能包含两种不同的数据类型的值:基本类型值和引用类型值.基本类型值指的是那些保存在栈

javascript变量作用域与内存

第四章 变量作用域与内存基本类型 5种Undefined Null Boolean Number String 两种变量类型 基本类型与引用类型注意:String 再其他语言中是引用类型,再javascri中为基本类型即:这五种基本类型是按值访问的 引用类型是按照引用访问的 动态的属性对于一个引用类型,一个引用变量被赋值后,可以为其添加属性,也可以删除与修改其属性var o = new object();o.name = "qi"; //可以为引用变量添加属性 变量的复制基本类型的复制

JavaScript变量作用域和内存问题(js高级程序设计总结)

1,变量 ECMAScript和JavaScript是等同的吗?个人认为是否定的.我的理解是这样的,ECMAScript是一套完整的标准或者说协议,而JavaScript是在浏览器上实现的一套脚本语言.也就是说,ECMAScript是JavaScript的父类标准.JavaScript是ECMAScript的具体实现.所有ECMAScript定义的数据类型或者语言特性实际上都是伪代码的形式规定的.当然如果可以,ECMAScript也可以有服务器实现,单片机实现(不一定恰当).如果说ECMAScr

读书笔记 - js高级程序设计 - 第四章 变量 作用域 和 内存问题

5种基本数据类型 可以直接对值操作 判断引用类型 var result = instanceof Array 执行环境 每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中 执行环境的销毁 某个执行环境中的所有代码执行完毕后 该环境被销毁 保存在其中的所有变量了函数定义也会随之销毁 作用域链中的对象 全局执行环境的变更对象始终都是作用域链中的最后一个对象 没有块级作用域 if 和 for 内的变量 外部也可以访问 标记清除 不同浏览器 只不过垃圾时间的长短不同 引

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

传递参数 ECMAScript所有函数参数都是按值传递的,即使对象在函数内部修改了参数的值,原始的引用任然不变,局部对象在函数执行完毕后被销毁

JavaScript变量作用域和内存问题(二)

执行环境是js中特别重要的概念,是指变量或者函数可以访问其他数据,定义自己的行为.每个执行环境都有一个与之相对应的变量对象,执行环境中定义的所有变量和函数都保存在这个变量中,我们看不到这个变量,但是后台可以看到.     全局变量的执行环境是最外围的执行环境,在web浏览器中,全局执行环境就是window对象,所以所有的函数和全局变量都可以作为window对象的一个属性.其他执行环境都是在函数和变量执行完毕后销毁内存,变量和函数也随之销毁,而全局变量也是在关闭页面或浏览器的时候销毁.    “

第四章 变量 作用域和内存问题

4.1变量 变量包含2种类型的值: 基本类型的值: 即undefined,null, string,number,boolean.   按值访问,可以操作保存在变量中实际的值, 不能添加属性. var name = "Nicholas"; name.age = 27; console.log(name.age); //undefined 引用类型的值:多个值构成的对象.JS不允许直接操作对象的内存空间.给一个对象添加属性是,是在实际的对象中添加. 俩种类型值的区别: 1.保存方式不同:

第四章 变量作用域和内存问题--笔记6

JavaScript没有块级作用域 使用var声明的变量会自动被添加到最近的环境中,如:在函数内部,最近的环境就是函数的局部环境,在with语句中,最近的环境就函数环境.如果初始化变量时没有使用var,则该变量自动被添加到全局环境. 在某个环境中读取或写入某个标识符时,就会在从作用域链的前端开始逐级向下查找,直至找到即停止搜索.

第四章 变量作用域和内存问题--笔记5(含问题)

作用域链得到延长的情况: try-catch语句的catch块:会创建一个新的变量对象,其中包含的是被抛出的错误对象声明. with语句:会将指定的对象添加到作用域链中. 问1:为什么url变成了buildUrl的变量,它不是在with中定义的吗? 答1:with语句关联了location对象,这意味着在with语句的代码块内部,每个变量首先被认为是一个局部变量,而如果在局部环境中找不到该变量的定义,就会查询location对象中是否有同名的属性,如果发现了同名属性,则以location对象属性

js基础之--变量 作用域和内存问题

基本类型:Undefind Null Boolean Number String 引用类型: 对象 在操作对象时,实际上实在操作对象的引用而不是实际的对象.为此,引用类型的值是按引用访问的. 从一个变量向另一个变量赋值引用类型的值,同样也会将存储在对象中的值赋值一份放到为新变量分配的空间中.不同的是,这个值的副本实际上是一个指针,而这个指针指向存储在堆中的一个对象 <script> var arr = {name:"jiayu"} doSomeThing(arr); con