我的一句话总结:原始值不管是变量赋值还是函数传递都不会改变原值,引用值不管是变量赋值还是函数传递,如果新变量重新赋值,则不会影响原引用值,如新变量是直接操作,就会影响原引用值。

  首先明确,值和类型是两个不同的概念。例如,null是null类型的唯一值、undefined是undefined类型的唯一值、而true和false是boolean类型仅有的两个值等。在任何语言中,值的操作都可以归纳为以下3个方面。

  复制值:即把值赋值给新变量,或者通过变量把值赋值给另一个变量、属性或数组元素。

  传递值:即把值作为参数传递给函数或方法。

  比较值:即把值与另一个值进行比较,看是否相等。

  由于值类型数据和引用型数据的值存在形式不同,自然操作它们的方法和所产生的结果也是不同的。注意,当值为值类型数据时,我们常称之为原始值或基本值;当值为引用型数据时,我们常称之为引用值或复合值。  

1.使用原始值

对于原始值来说,其操作的3个层面说明如下。

1)复制值

在赋值语句中,操作的过程将会产生一个实际值的副本,副本的值和实际值之间没有任何联系,它们独自位于不同的栈区或者堆区。这个副本可以存储变量、对象的属性和数组的元素。例如:

var n = 123, a, b = [], c = {};
a = n; // 复制数字123
b[0] = n; // 复制数字123
c.x = n; // 复制数字123
(a == b[0]) && (a == c.x) && (b[0] == c.x) && alert("复制的值都是相等的"); // 检测它们的值都是相等的

  

在上面示例中,分别把值123复制3份给变量a、数组b和对象c,虽然它们的值是相等的,但是它们之间是相互独立的。

2)传递值

当把值传递给函数或方法时,传递的值仅是副本,而不是值本身。例如,如果在函数中修改传递进来的值时,结果只能够影响这个参数值的副本,并不会影响到原来的值。

var a = 123;        // 原来的值  

function f(x){
x = x + x;
}
f(a); // 调用函数修改传递的值 alert(a); // 查看变量a的值是否受影响,返回值为123,说明没有变化

  

3)比较值

在上面的示例中我们也可以看到,当对原始值进行比较时,进行逐字节的比较来判断它们是否相等。比较的是值本身,而不是值所处的位置,固然比较的结果可能会相等,但只是说明它们所包含的字节信息是相同的。

2.使用引用值

对于引用值来说,其操作的3个层面说明如下。

1)复制值

在赋值语句中,所赋的值是对原值的引用,而不是原值副本,更不是原值本身。也就是说,进行赋值之后,变量保存的都是对原值的引用(即原值的存储地址)。当在多个变量、数组元素或对象属性中间复制时,它们都会与原始变量保存的引用相同。

所有引用具有相同的效力和功能,都可以执行操作,如果通过其中的一个引用编辑数据,这种修改将会在原值及其他相关引用中体现出来。例如:

var a = [1,2,3];    // 赋值数组引用
b = a; // 复制值
b[0] = 4; // 修改变量b中第一个元素的值
alert(a[0]); // 返回4,显示变量a中第一个元素的值也被修改为4

  但是,如果给变量b重新赋予新值,则新值不会影响原值内容。例如:

var a = [1,2,3];    // 赋值数组引用
b = a; // 复制值
b = 4; // 为变量b重写赋值
alert(a[0]); // 变量a的内容保持不变

  重复赋值实际上是覆盖变量对原值的引用,变为另一个值的副本或对其引用。所以不会对原值产生影响,演示示意图如图4-2所示。

  

  

2)传递值

当使用引用将数据传递给函数时,传递给函数的也是对原值的一个引用,函数可以使用这个引用来修改原值本身,任何修改在函数外部都是可见的。例如:

var a = [1,2,3];
function f(x){
x[0] = 4; // 在函数中修改参数值
}
f(a); // 传递引用值
alert(a[0]); // 返回4,原值发生变化

  请注意,在函数内修改的是对外部对象或数组的引用,而不是对象或数组本身的值。在函数内可以使用引用来修改对象的属性或数组的元素,但是如果在函数内部使用一个新的引用覆盖原来的引用,那么在函数内部的修改就不会影响原引用的值,函数外部也是看不到的。

var a = [1,2,3];
function f(x){
x = 4; // 在函数中修改参数值
}
f(a); // 传递引用值
alert(a[0]); // 返回1,原值不会发生变化

  

3)比较值

当比较两个引用值时,比较的是两个引用地址,看它们引用的原值是否为同一个副本,而不是比较它们的原值字节是否相等。当对两个不同值进行引用时,尽管它们具有相同的字节构成,但是这两个引用的值却是不相等的。

var a = new Number(1);    // 引用值a
var b = new Number(1); // 引用值b
var c = a; // 把a的引用赋值给c
alert(a==b); // 返回false
alert(a==c); // 返回true

  所以,{} == {},[] == [],都返回false。因为引用地址不同。

  总之,对于任何语言来说,使用值和使用引用都是数据操作的两种基本方法。当我们操作数据时,要采用什么方法来进行处理,主要看数据的类型。值类型和引用型数据参与运算的方式不同,值类型数据通过使用值来操作数据,而引用型数据使用引用来操作数据。运算方式的不同,自然所产生的结果也不同。我们不妨再看一个示例:

var s = "abc";                  // 字符串,值类型数据
var o = new String(s); // 字符串对象,被装箱后的字符串 function f(v){ // 运算函数
v.toString = function(){ // 修改参数的方法toString()
return 123;
};
}
f(s); // 传入值
alert(s); // 返回字符串"abc",说明运算没有对原数据造成影响
f(o); // 传入引用
alert(o); // 返回数值123,说明运算已经影响到原数据的内部结构

  值类型是以实际值参与运算的,因此与原数据没有直接联系。而引用型以引用地址参与运算,计算的结果会影响到引用地址所关联的堆区数据块。但是,有一点例外,对于JavaScript的字符串来说,它的操作方法就比较复杂,详情请google!

JavaScript数据操作--原始值和引用值的操作本质的更多相关文章

  1. javascript原始值和引用值类型及区别

    原始值和引用值类型及区别 首先,原始值和引用值类型都是js中的数据类型,为了充分利用存储空间,定义了不同的数据类型,而且js是弱类型,动态语言,数据类型可变. 原始值(简单数据类型) 存储在栈中的简单 ...

  2. ES6 学习笔记(三)原始值与引用值

    总结: 1.原始值,表示单一的数据,如10,"abc",true等. 1.1. ES的6种原始值: Undefined.Null.Boolean.Number.String.Sym ...

  3. JS中原始值和引用值的储存方式

    在ECMAscript中,变量可以存放两种类型的值,即原始值和引用值 原始值指的是代表原始数据类型的值,也叫基本数据类型,包括:Number.Stirng.Boolean.Null.Underfine ...

  4. JS中原始值和引用值分析

    JS中变量中两种类型的值:原始值,引用值 原始值是存储在栈(stack)中的简单数据段,也就是说,它们的值直接存储在变量访问的位置. var x = 1; //1就是一个原始值,变量x中存放的就是原始 ...

  5. Js 中的原始值和引用值

    最近遇写 node.js 时到一个问题,把对象当赋值给数组成员时总是出错,比如下面的代码, var Arr = new Array(); var Obj = new Object(); for(var ...

  6. ECMAScript 原始值和引用值

    原始值和引用值 在ECMAScript中,变量可以存在两种类型的值,即原始值和引用值 原始值 存储

  7. JavaScript-原始值和引用值

    一.原始值和引用值的概念 在 ECMAScript 中,变量可以存在两种类型的值,即原始值和引用值. 1.1 原始值 (1)原始值指的是 原始类型 的值,也叫 基本类型,例如 Number.Stirn ...

  8. JavaScript检测原始值、引用值、属性

    上周写过一篇读书笔记<编写可维护的JavaScript>之编程实践,其中 第8章 避免『空比较』是博主在工作中遇坑较多的雷区,所以特此把该章节重新整理分享,希望大家不再坑队友(>﹏& ...

  9. JS浅谈原始值与引用值操作

    值的操作分为三大类:复制,传递,比较 一:复制 原始值 let a = 10; let b = a; 注释:2018-7-30 17:33:49 1 原始类型的值都是存放在栈内存当中,所以他们的赋值操 ...

随机推荐

  1. 【BZOJ 1568】【JSOI 2008】Blue Mary开公司

    经典的splay维护凸壳,但是看了看zky学长的题解最后决定写线段树维护标记永久化. Round1考到了这个之后一直没有理解标记永久化,CTSC也因为自己的缺陷丢掉了一些部分分,so sad 看来以后 ...

  2. tomcat+javaWeb+spring的一个都市供求管理系统

    这个作为自己学习javaweb的第一个小项目,也是跟着视频自己学的,是来自java1234的小锋写的,那边有很多java视频可以作为学习参考哦 , 视频中使用的是tomcat作为后端,也( •̀ ω ...

  3. 绘图: Stroke, Brush

    Stroke - 笔划 Brush - 画笔 示例1.演示“Stroke”相关知识点Drawing/Stroke.xaml <Page x:Class="Windows10.Drawi ...

  4. Python中的GIL

    •start 线程准备就绪,等待CPU调度 •setName 为线程设置名称 •getName 获取线程名称 •setDaemon 设置为后台线程或前台线程(默认) 如果是后台线程,主线程执行过程中, ...

  5. bzoj 1101 zap

    gcd(x,y)=d-->gcd(x/d,y/d)=1. 即求Σ(i<=n/d)Σ(j<=m/d) e(gcd(i,j)) 因为e=miu×1,可以卷积. 因为多组询问,需要sqrt ...

  6. 【BZOJ-1670】Building the Moat护城河的挖掘 Graham扫描法 + 凸包

    1670: [Usaco2006 Oct]Building the Moat护城河的挖掘 Time Limit: 3 Sec  Memory Limit: 64 MBSubmit: 464  Solv ...

  7. 【BZOJ-3438】小M的作物 最小割 + 最大权闭合图

    3438: 小M的作物 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 825  Solved: 368[Submit][Status][Discuss ...

  8. bzoj1102: [POI2007]山峰和山谷Grz

    #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #i ...

  9. Visual Studio 2015 未响应/已停止工作的问题解决

    在我把之前项目从10版本升级到15版本的时候,一打开转换的项目过几分钟立马卡死,出现未响应/已停止工作的问题,我试过了很多方法: 1.升级操作系统,8.1升级10,没用! 2.重装VS,没用! 3.卸 ...

  10. 利用TabHost制作QQ客户端标签栏效果(低版本QQ)

    学习一定要从基础学起,只有有一个好的基础,我们才会变得更加的perfect 下面小编将利用TabHost制作QQ客户端标签栏效果(这个版本的QQ是在前几年发布的)…. 首先我们看一下效果: 看到这个界 ...