变量、作用域和内存问题

从前面的学习中,我们可以感觉到,JavaScript的变量与其他语言的变量有很大区别。JavaScript变量松散类型的本质,决定了它只是在特定时间用于保存特定值的一个名字而已。由于不存在定义某个变量必须保存何种数据类型值的规则,变量的值以及其数据类型可以在脚本的生命周期内改变。

  1. 基本类型和引用类型的值

ECMAScript变量可能包含两种数据类型的值:基本类型值和引用类型值。基本类型值指的是简单的数据段,而引用类型指那些可能由多个值构成的对象。基本数据类型是按值访问的,因为可以操作保存在变量中的实际的值。操作对象时,实际上是操作对象的引用而不是实际的对象。引用类型的值是按引用访问的。

1.1 动态的属性

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

 <script>
        var  person=new Object();
        person.name="JiaHua Chen";
        alert(person.name);

    </script>

很明显,并不能给基本类型的值添加属性,尽管这样做不会导致任何错误。例如:

 <script>
        var  person=new Object();
        person.age=27;
        alert(person.age);

    </script>

执行后发现,该属性值并没有不见。(→_→)

1.2 复制变量值

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

<script>
        var num1=10;
        var num2=num1;
        document.write("num1="+num1+",num2="+num2+"<br>");
        num2=20;
        document.write("num1="+num1+",num2="+num2+"<br>");
    </script>

num2是num1的一个副本,可以看到复制的num2和num1是完全独立的,互不影响。

当从一个变量向另一个变量复制引用类型的值时,同样也会将存储在变量对象的值复制放到新变量分配的空间中。该值的副本实际上是一个指针,而这个指针指向存储在堆中的一个对象。两个变量实际上引用同一个对象。例如:

<script>
        var person=new Object();
        person.name="喜剧演员";
        var person2=person;
        document.writeln("Person2 Name:"+person2.name+"<br>");
        person.name="追光者";
        document.writeln("Person2 Name:"+person2.name+"<br>");
    </script>

person和person2两个变量指向同一个对象,所以person的name属性值改变之后,person2的name属性也随之改变。

1.3 传递参数

ECMAScript中所有函数的参数都是按值传递的。也就是把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。访问变量有按值和按引用两种方式,而参数只能按值传递。在向参数传递基本类型的值时,被传递的值会被复制给一个局部变量;在向参数传递引用类型的值时,会把这个值在内存中的地址复制给一个局部变量,因此这个局部变量的变化会反映在函数的外部。

  <script>
        var num=20;
        function add(num) {
            num+=10;
            return num;
        }
        var result=add(num);
        document.write("num="+num+",result="+result+"<br>");
    </script>

可以看到在调用add()函数之后,num的值并没有发生变化,可以说明的是值传递。

如果向参数传递的是引用类型的变量的话:

<script>
        var person=new Object();
        person.name="喜剧演员";
        function changeName(obj) {

            obj.name="追光者";
        }

        changeName(person);
        document.write("Name:"+person.name);
    </script>

发现在调用changeName()函数之后,发现person的name属性的值变化了。有种 错误的认知:在局部作用域中修改的对象会在全局作用域中反映出来,就说明参数是按引用传递的。为了证明对象是按值传递的,需要看一下面的例子:

<script>
        var person=new Object();
        function changeName(obj) {

            obj.name="追光者";
            obj=new Object();
            obj.name="喜剧演员"
        }

        changeName(person);
        document.write("Name:"+person.name);
    </script>

发现打印出来的仍然是“追光者”。这说明即使在函数内部修改了参数的值,但原始的引用仍然保持不变。实际上,当在函数内部重写obj时,这个变量引用的就是一个局部对象了。而这个局部对象会在函数执行完毕之后立即被销毁。

1.4 检测类型

使用typeof操作符去检测变量是基本类型还是引用类型。

<script>
         var s="AAAa";
         var b=true;
         var i=22;
         var u;
         var o=new Object();
         var n=null;
         document.write(typeof s+"<br>");
         document.write(typeof b+"<br>");
         document.write(typeof i+"<br>");
         document.write(typeof u+"<br>");
         document.write(typeof o+"<br>");
         document.write(typeof n+"<br>");
    </script>

u的类型的undefined,n和o的类型为object。

虽然在检测基本数据类型时,typeof非常好用,但是在检测引用类型的值时,这个操作符的作用不大。通常,我们想知道的是某个值是什么类型的对象而不是知道它是个对象,为此需要使用instanceof操作符。如果变量是给定引用类型的实例,那么就会返回true。

<script>
         var array=new Array("AASA","ASas");
         var o=new Object();
         var reg=new RegExp("AA","SA");
         alert(array instanceof Array);
         alert(o instanceof Object);
         alert(reg instanceof RegExp);
    </script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值