JavaScript中的值类型与引用类型

值类型

值类型的数据:存储的是数据本身的变量。

值类型(基本数据类型)包括number、boolean、string、undefined、null。
值类型的数据在内存中占有固定大小的空间,它是存储在栈(stack)中的简单数据,也就是说,值类型的值直接存储在变量访问的位置。
值类型的数据在内存中的存储如下:
这里写图片描述

引用类型

引用类型的数据:存储的是数据在内存中的地址,数据在内存中单独存储。

引用类型包括:Object Array Function等
引用类型的值大小不固定,因此不能把它们保存到栈内存中,但内存地址大小是固定的,因此可以将内存地址保存在栈内存中,把数据存放到堆中。这样当查询引用类型的变量时,先从栈中读取内存地址,然后根据地址找到堆中的值。也就是说,存储在变量处的值是一个指针(point),指向存储对象的内存处。
这里写图片描述

为什么会有栈内存和堆内存之分?

通常与垃圾回收机制有关。为了使程序运行时占用的内存最小。
当一个方法执行时,每个方法都会建立自己的内存栈,在这个方法内定义的变量将会逐个放入这块栈内存里,随着方法的执行结束,这个方法的内存栈也将自然销毁了。因此,所有在方法中定义的变量都是放在栈内存中的;
当我们在程序中创建一个对象时,这个对象将被保存到运行时数据区中,以便反复利用(因为对象的创建成本通常较大),这个运行时数据区就是堆内存。堆内存中的对象不会随方法的结束而销毁,即使方法结束后,这个对象还可能被另一个引用变量所引用(方法的参数传递时很常见),则这个对象依然不会被销毁,只有当一个对象没有任何引用变量引用它时,系统的垃圾回收机制才会在核实的时候回收它。

值类型与引用类型的赋值

  • 值类型的赋值

    直接将存储的数据复制一份进行赋值,两份数据在内存中是完全独立的
    比如: var a = 30; var b= a;这两句代码在内存中的体现是:
    这里写图片描述

  • var a = 9;表示变量a存储的是数字9

  • 将数据拷贝一份,也就是将9拷贝一份,这个时候内存中有两个9
  • 将拷贝的9赋值给b
  • 因为值类型的赋值是直接把数据也复制了一份,a和b是单独的存储空间,任意改变a 和b的值,都不会给对方造成影响。
    看例子:
var a= 9;
var b=a;
a = 10;
console.log(a,b); 
输出的结果是//a = 10, b = 9
  • 引用类型赋值

    引用类型赋值的时候,是将变量中存储的地址复制一份单独存储,但是两个变量共享同一个对象
    修改其中一个对象,两外一个引用来访问的时候,也会访问到修改后的对象

var p = {name:”kong”, age:20};var p1 = p;

上面两句代码,在内存中的体现为:
这里写图片描述

  • var p = {name:”kong”, age:20};p中存储的是对象的地址;
  • 赋值就是将变量p中存储的数据,也就是地址拷贝一份, 然后将该数据赋值给p1;
  • 此时内存中只有 1 个对象,变量p和p1同时指向这个对象.
  • 由于p和p1 都是指向同一个对象,如果修改p.name 那么p1.name也会随之改变。
 var p={
        name:"kong",
        age:20
     }
     var p1 = p;
     p.name ="diligentkong";
     p.age = 23;
    console.log(p2.name, p2.age); 
输出的结果是: p1.name = diligentkong p1.age = 23

具体可以这样解释:

  1. 修改p时,先找到p的地址,根据p的地址找到存储的具体数据,然后进行修改:p.name =”diligentkong”;p.age = 23;
  2. 此刻要输出p1的name和age的时候,要先找到p1的地址,根据p1的地址找到对应的数据。而p和p1的地址对应着相同的数据,p修改了数据之后,p1的数据相应的也会改变啦。

引用类型和值类型在函数中的使用

 var num = 9;
   function changeNum (num){
     num = 10;
     console.log(num);  // 10
   }
   changeNum(num);
   console.log(num);   //9

可以这样解释:
值类型做函数的参数,
函数内部的变量,也就是形参和实参只是简单的赋值操作,两个数据独立存储于内存中的。
在函数内部对形参进行修改,不会影响外面的变量。
这里写图片描述

var obj = {
       name : "kong"
   }
   function changeName(para){

        para.name = "diligentkong";

   }

   changeName(obj);

   console.log(obj.name); // diligentkong

引用类型做函数的参数
还是把实参存储的地址赋值给了形参,在函数内部,形参同样也指向该对象,所以,在函数内部对该对象进行修改,会影响到外面的变量。
这里写图片描述

这样修改 最终会变成什么呢?
  var obj = {
       name : "kong"
   }
   function changeName(para){

        para.name = "diligentkong";

        para = {
            name:"haha"
        };
        para.name = "kong";

   }

   changeName(obj);

你猜的结果是什么呢?

这里写图片描述
所以最后打印的还是diligentkong;
注意:如果在函数内部重新创建对象,为该形参赋值,那么实参和形参两个对象将不再有关系,修改其中一个,另外一个不受影响。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值