专栏首页大前端_Web深入解析js中基本数据类型与引用类型,函数参数传递的区别

深入解析js中基本数据类型与引用类型,函数参数传递的区别

版权声明:本文为吴孔云博客原创文章,转载请注明出处并带上链接,谢谢。 https://blog.csdn.net/wkyseo/article/details/51484506

ECMAScript的数据有两种类型:基本类型值和引用类型值,基本类型指的是简单的数据段,引用类型指的是可能由多个值构成的对象。

Undefined、Null、Boolean、Number和String是值类型,其他都是引用类型。其他语言String是以对象的形式表示,ECMAScript放弃了这一传统。

内存中的存储区域

值类型存储在栈中,引用类型存储在堆中。内存中是分为两个区域的,一个是栈:它就是专门存放值类型的,但是它有一定的存储空间,只能存放基本数据类型的数据和对象类型的引用地址也叫哈希码。存储在栈里面的基本数据类型的值都是有最大值和最小值的,不能超出它的默认范围;二就是堆:它的存储空间大,是用来存储“数组类型”和“对象类”的数据的。存储在堆里的引用类型数据是没有固定大小的,比如说一个对象类型的数据,你可以往里面存放一个字符、两个字符·····更多,不管你存多少它都会把你存放的数据在内存的堆里面开辟一块空间来存储,在栈里面开辟一块空间来存放引用地址,栈是后进先出的。

复制变量值

  • 复制基本类型值 会在上重新分配一个内存空间,来存当前赋值的变量,这两个变量可以参与任何操作而不会相互影响。
var name1 = 'kenny';
var name2 = name1;
name2 // 'kenny'
name2 = 'wukongyun';
name1 //'kenny'
  • 复制引用类型值

将存储在变量对象中的值复制一份放到新变量分配的空间中(新变量的指针存储在栈上),复制的实际上是一个指针,而这个指针指向存储在堆中的一个对象。两个变量实际上引用的是同一个对象。改变其中一个变量,就会影响另一个变量。

var obj1 = {name: 'kenny'};
var obj2 = obj1;
obj1.name = 'kongyun';
obj2.name // 'kongyun'

参数的传递

ECMAScript所有的函数的参数都是按值传递的。函数外部的值赋值给函数内部的参数,与一个变量复制到另一个变量一样。基本类型值的传递和基本类型一样,引用类型的传递和引用类型的复制一样。

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

引用类型也是按值传递

function setName(obj) {
    obj.name = 'kenny';
    obj = new Object();
    obj.name = 'kongyun';
}

var  person = new Object();
setName(person);
console.log(person.name); // 'kenny'

即使在函数内部修改了参数的值,但原始的引用(person对象,存储在堆上)仍保持不变。具体传递的obj不是指针而是指针引用的对象(副本copy)。实际上,当在函数内部重写obj时,这个变量的引用的就是一个局部对象了,而这个局部对象会在函数执行完毕后立即被销毁。

类似于这种例子 - -

var a = [1, 2];
var b = a;
a = {a:1, b:2};//虽然a改变了,但是b依然没变,值传递,复制了个指针

扩展:值传递与引用传递

  • 值传递:call by value
  • 引用传递:call by Call by reference

值传递和引用传递,属于函数调用时参数的求值策略(Evaluation Strategy),这是对调用函数时,求值和传值的方式的描述,而非传递的内容的类型(内容指:是值类型还是引用类型,是值还是指针)。值类型/引用类型,是用于区分两种内存分配方式,值类型在调用栈上分配,引用类型在堆上分配。一个描述内存分配方式,一个描述参数求值策略,两者之间无任何依赖或约束关系。

区别

值传递

引用传递

根本区别

会创建副本(copy)

不创建副本

所以

函数中无法改变原始对象

函数中可以改变原始对象

对于值传递,无论是值类型还是引用类型,都会在调用栈上创建一个副本,不同是,对于值类型而言,这个副本就是整个原始值的复制。而对于引用类型而言,由于引用类型的实例在堆中,在栈上只有它的一个引用(一般情况下是指针),其副本也只是这个引用的复制,而不是整个原始对象的复制。

这便引出了值类型和引用类型(这不是在说值传递)的最大区别:值类型用做参数会被复制,但是很多人误以为这个区别是值类型的特性。其实这是值传递带来的效果,和值类型本身没有关系。只是最终结果是这样。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • C#中值类型和引用类型及类型的转换

    版权声明:本文为吴孔云博客原创文章,转载请注明出处并带上链接,谢谢。 https://blog.csdn.net/wkyseo/articl...

    空空云
  • 不定高多行溢出文本省略

    大家应该都知道用text-overflow:ellipsis属性来实现单行文本的溢出显示省略号(…)。当然部分浏览器还需要加宽度width属性。

    空空云
  • NodeJS学习二CommonJS规范

    Node程序由许多个模块组成,每个模块就是一个文件。Node模块采用了CommonJS规范。

    空空云
  • Dart学习笔记

    Dart中,不像其他语言存在基本类型与类类型,Dart中所有类型(包括int等)都是继承自Object的类型 字符串字符为UTF16编码,小数都为double类...

    歪歪梯
  • js == 和 ===

    FlyLolo
  • 线性表

    在java中可以坐飞机到指定的目的地,但是你不能开飞机(安全)。但是在C++中可以自己开飞机(操作飞机)--具有危险性。

    Noneplus
  • 线性表

    - 多个元素的线性表,第一个元素没有前驱,最后一个元素没有后继,其他元素有且仅有一个前驱,一个后继。

    Noneplus
  • javascript关于forEach使用方式

    明明是一样的函数执行结果没有达到自己需要的那样,为什么呢?今天不小心踩到了这个坑。

    杭州前端工程师
  • 《Effective Java》——读后总结

    这本书在Java开发的行业里,颇有名气。今天总算是粗略的看完了...后面线程部分和序列化部分由于心浮气躁看的不仔细。这个月还剩下一周,慢慢总结消化。

    Java后端工程师
  • MySQL 高性能表设计规范

    良好的逻辑设计和物理设计是高性能的基石, 应该根据系统将要执行的查询语句来设计schema, 这往往需要权衡各种因素。

    高广超

扫码关注云+社区

领取腾讯云代金券