JavaScript原始值/基本类型、引用值/引用类型比较

原始值和引用值存储方式、可改变/不可改变、相互比较的方法

JJavaScript 中的原始值/基本类型(undefained、null、布尔值、数字和字符串)与引用值/引用类型(对象,数组,函数等)有着根本的区别。

值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol。

引用数据类型:对象(Object)、数组(Array)、函数(Function)。

1.存储方式

原始值:
存储在栈(stack)中的简单数据段,也就是说,它们的值直接存储在变量访问的位置。

var name = 'jozo';
var city = 'guangzhou';
var age = 22;

在这里插入图片描述

引用值:
存储在堆(heap)中的对象,也就是说,存储在变量处的值是一个指针(point),指向存储对象的内存处。

var person1 = {name:'jozo'};
var person2 = {name:'xiaom'};
var person3 = {name:'xiaoq'};

在这里插入图片描述

为变量赋值时,JavaScript 的解释程序必须判断该值是原始类型,还是引用类型。由于这些原始类型占据的空间是固定的,所以可将他们存储在较小的内存区域——栈中。这样存储便于迅速查寻变量的值。

在许多语言中,字符串都被看作引用类型,而非原始类型,因为字符串的长度是可变的。JavaScript 打破了这一传统。

如果一个值是引用类型的,那么它的存储空间将从堆中分配。由于引用值的大小会改变,所以不能把它放在栈中,否则会降低变量查寻的速度。相反,放在变量的栈空间中的值是该对象存储在堆中的地址。地址的大小是固定的,所以把它存储在栈中对变量性能无任何负面影响。如下图所示:

栈中的原始值与堆中的引用值:

在这里插入图片描述

2.表现方式

原始值是不可更改的:任何方法都无法更改(或“突变”)一个原始值(你无法修改值本身,你只能给代表它的变量重新赋值,将原来的值覆盖)。

对数字和布尔值来说显然如此——改变数字的值本身就说不通,而对字符串来说就不那么明显了,因为字符串看起来像由字符组成的数组。我们期望可以通过指定索引来修改字符串中的字符。实际上,JavaScript 是禁止这样做的,字符串中的所有的方法看上去返回了一个修改后的字符串,实际上返回的是一个新的字符串值。例如:

var s = "hello"; //定义一个由小写字母组成字符串
s.toUpperCase(); //=>“HELLO”,但并没有改变s的值
s;               //=>“hello”:原始字符串的值并未改变。

3.比较

原始值的比较是值的比较:只有在它们的值相等时它们才相等。这对数字、布尔值、null和underfined来说听起来有点难懂,并没有其他办法来比较他们。同样,对于字符串来说则并不明显:如果比较两个单独的字符串,当且仅当他们的长度相等且每个索引的字符都相等时,JavaScript 才认为它们相等。

引用值和原始值不同,首先,它们是可变的——它们的值是可修改的:

var o = {x:1};  //定义一个对象
o.x = 2;        //通过修改对象属性值来更改对象
o.y = 3;        //再次更改这个对象,给它增加一个新属性
var a = [1,2,3];//数组也是可修改的
a[0] = 0;       //更改数组的一个元素
a[3] = 4;       //给数组增加一个新元素

引用值的比较并非值的比较:即使两个引用值包含同样的属性及相同的值,它们也是不相等的。各个索引元素完全相等的两个数组也不相等:

var o = {x:1},p = {x:1};//具有相同属性的两个对象
o === p;                //=> false:两个单独的对象不严格相等
var a = [],b = [];      //两个单独的空数组
a === b;                //=> false:两个单独的数组不严格相等

我们通常将对象称为引用类型(reference type),以此来和 JavaScript 的基本类型区分开来。依照术语的叫法,对象值都是引用(reference),对象的比较均是引用的比较:当且仅当它们引用同一个基对象时,它们才相等。并且,修改引用值时,基对象也会被修改:

var a = []; //定义一个引用空数组的变量a
var b = a;  //变量b引用同一个数组
b[0] = 1;   //通过变量b来修改引用的数组
a[0];       //=> 1:变量a也会被修改
a === b;    //=> true:a和b引用同一个数组,因此它们相同

在这里插入图片描述

如上代码所示,将对象(或数组)赋值给一个变量,仅仅是赋值的引用值:对象本身并没有复制一次。如果你想得到一个对象或数组的副本,则必须显式复制对象的每个属性或数组的每个元素,如下代码:

var a = [1,2,3];
var b = [];
for(var i = a.length;i--;){
    b[i] = a[i];
}

同样的,如果我们想比较两个单独的对象或者数组,则必须比较它们的属性或元素:

function equalArrays(a,b){
    if(a.length !== b.length) return false;
    for(var i = a.length;i--;){
        if(a[i] !== b[i]) return false;
    }
    return true;
}

总结:

在使用的时候,需要注意修改引用对象,基对象也会被修改,如果你想将一个原始的数据对象暂存在本地变量中,应该通过循环来完成数组复制,否则会引起不必要的麻烦。

主要参考文章:

http://laichuanfeng.com/study/javascript-immutable-primitive-values-and-mutable-object-references/

https://www.cnblogs.com/focusxxxxy/p/6390536.html

还可以参考文章:

https://www.cnblogs.com/youxin/archive/2013/05/05/3060530.html

http://www.cnblogs.com/youxin/archive/2012/08/23/2653292.html

·

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值