值和引用

在许多编程语言中,赋值和参数传递可以通过值复制或者引用复制来完成,这取决于我们使用什么语法。

例如,在 C++ 中如果要向函数传递一个数字并在函数中更改它的值,就可以这样来声明参 数 int& myNum,即如果传递的变量是 x,myNum 就是指向 x 的引用。引用就像一种特殊的指 针,是来指向变量的指针(别名)。如果参数不声明为引用的话,参数值总是通过值复制 的方式传递,即便对复杂的对象值也是如此。

JavaScript 中没有指针,引用的工作机制也不尽相同。在 JavaScript 中变量不可能成为指向 另一个变量的引用。

JavaScript 引用指向的是值。如果一个值有 10 个引用,这些引用指向的都是同一个值,它 们相互之间没有引用 / 指向关系。

JavaScript 对值和引用的赋值 / 传递在语法上没有区别,完全根据值的类型来决定

下面来看一个例子:

简单值(即标量基本类型值,scalar primitive)总是通过值复制的方式来赋值 / 传递,包括 null、undefined、字符串、数字、布尔和 ES6 中的 symbol。

复合值(compound value)——对象(包括数组和封装对象)和函数,则总 是通过引用复制的方式来赋值 / 传递。

上例中 2 是一个标量基本类型值,所以变量 a 持有该值的一个复本,b 持有它的另一个复 本。b 更改时,a 的值保持不变。

c 和 d 则分别指向同一个复合值 [1,2,3] 的两个不同引用。请注意,c 和 d 仅仅是指向值 [1,2,3],并非持有。所以它们更改的是同一个值(如调用 .push(4)),随后它们都指向更 改后的新值 [1,2,3,4]。

由于引用指向的是值本身而非变量,所以一个引用无法更改另一个引用的指向。

b=[4,5,6] 并不影响 a 指向值 [1,2,3],除非 b 不是指向数组的引用,而是指向 a 的指针, 但在 JavaScript 中不存在这种情况!

函数参数就经常让人产生这样的困惑:

我们向函数传递 a 的时候,实际是将引用 a 的一个复本赋值给 x,而 a 仍然指向 [1,2,3]。 在函数中我们可以通过引用 x 来更改数组的值(push(4) 之后变为 [1,2,3,4])。但 x = [4,5,6] 并不影响 a 的指向,所以 a 仍然指向 [1,2,3,4]。

我们不能通过引用 x 来更改引用 a 的指向,只能更改 a 和 x 共同指向的值。

如果要将 a 的值变为 [4,5,6,7],必须更改 x 指向的数组,而不是为 x 赋值一个新的数组。

从上例可以看出,x.length = 0 和 x.push(4,5,6,7) 并没有创建一个新的数组,而是更改 了当前的数组。于是 a 指向的值变成了 [4,5,6,7]。

请记住:我们无法自行决定使用值复制还是引用复制,一切由值的类型来决定。

如果通过值复制的方式来传递复合值(如数组),就需要为其创建一个复本,这样传递的 就不再是原始值。例如:

foo( a.slice() );

slice(..) 不带参数会返回当前数组的一个浅复本(shallow copy)。由于传递给函数的是指 向该复本的引用,所以 foo(..) 中的操作不会影响 a 指向的数组。

相反,如果要将标量基本类型值传递到函数内并进行更改,就需要将该值封装到一个复合 值(对象、数组等)中,然后通过引用复制的方式传递。

这里 obj 是一个封装了标量基本类型值 a 的封装对象。obj 引用的一个复本作为参数 wrapper 被传递到 foo(..) 中。这样我们就可以通过 wrapper 来访问该对象并更改它的属 性。函数执行结束后 obj.a 将变成 42。

这样看来,如果需要传递指向标量基本类型值的引用,就可以将其封装到对应 的数字封装对象中。

与预期不同的是,虽然传递的是指向数字对象的引用复本,但我们并不能通过它来更改其 中的基本类型值:

原因是标量基本类型值是不可更改的(字符串和布尔也是如此)。如果一个数字对象的标 量基本类型值是 2,那么该值就不能更改,除非创建一个包含新值的数字对象。

x = x + 1 中,x 中的标量基本类型值 2 从数字对象中拆封(或者提取)出来后,x 就神不 知鬼不觉地从引用变成了数字对象,它的值为 2 + 1 等于 3。然而函数外的 b 仍然指向原 来那个值为 2 的数字对象。

相对而言,前面用 obj 作为封装对象的办法可能更好一些。这并不是说数字等封装对象没 有什么用,只是多数情况下我们应该优先考虑使用标量基本类型。

引用的功能很强大,但有时也难免成为阻碍。赋值 / 参数传递是通过引用还是值复制完全 由值的类型来决定,所以使用哪种类型也间接决定了赋值 / 参数传递的方式。

引用js_js值和引用相关推荐

  1. C++ 笔记(15)— 引用(声明引用、引用作为参数、引用作为函数返回值、const 用于引用)

    引用是变量的别名.也就是说,它是某个已存在变量的另一个名字.一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量. 1. 创建引用 要声明引用,可使用引用运算符 & ,如下面的 ...

  2. 2020-09-22C++学习笔记之引用1(1.引用(普通引用)2.引用做函数参数 3.引用的意义 4.引用本质5.引用结论 6.函数返回值是引用(引用当左值)7测试代码)

    2020-09-22C++学习笔记之引用1(1.引用(普通引用)2.引用做函数参数 3.引用的意义 4.引用本质5.引用结论 6.函数返回值是引用(引用当左值)7测试代码) 1.引用(普通引用) 变量 ...

  3. 你真的了解C#中的值和引用吗?(上)

    术语解释 在阅读本文之前,你需要了解以下这几个术语是不同的:值.引用.值类型.引用类型. C#中有三种值(value),分别是值类型实例的值.引用类型实例的值和引用. 值类型表达式的值是数据本身. 引 ...

  4. 012_原始值和引用值

    1. 在JavaScript中, 变量可以存在两种类型的值, 即原始值和引用值. 2. 原始值 2.1. 存储在栈(stack)中的简单数据段, 也就是说, 它们的值直接存储在变量访问的位置. 2.2 ...

  5. C++ 函数的引用返回值

    C++ 函数的引用返回值 2009-09-17 09:29 引用是给变量取一个别名,所以引用传递会直接进行变量本身的传递.它的最大好处是可以把别处对变量的改变保留下来,第二好处是它提高了性能:如果函数 ...

  6. mysql group_concat distinct,如何在MySQL中使用GROUP_CONCAT和CONCAT与DISTINCT引用单列值?...

    为此,您可以将group_concat()与一起使用replace().让我们首先创建一个表-mysql> create table DemoTable1799 ( EmployeeId var ...

  7. PHP的引用传值值传递

    // 值传递是并排的 一个变其他不变 // // 引用传值是串行的 一个变都变 // 函数内外其实是不一样的: // 值传递使用值传递,函数内外其实不是同一个变量了 // 引用传递是地址传递,函数内外 ...

  8. c语言调用oracle函数返回值吗,C语言通过值和引用函数

    . 将参数值或数据传递给C语言函数有两种方法:通过值调用和通过引用调用.原始值在通过值调用时不修改,但通过引用调用时,在函数中可进行修改. 下面将分别讲解如何通过值调用和通过引用调用,并用使用示例逐个 ...

  9. PHP javascript 值互相引用(不用刷新页面)

    PHP javascript 值互相引用的问题 昨天通过EMAIL给一些公司投了简历,希望他们能给我一份工作,今天其中一家公司的人给我打电话,大意是要我做一点东西(与AJAX有关) 给他们看,我听打电 ...

最新文章

  1. Java学习总结:57(Properties子类)
  2. 分享Kali Linux 2016.2第47周虚拟机
  3. 20189222 《网络攻防实践》 第四周作业
  4. [深度学习] 自然语言处理 --- Bert开发实战 (Transformers)
  5. [react] 为何说虚拟DOM会提高性能?
  6. Python多线程--互斥锁、死锁
  7. fence机制 linux_Linux ha fence设备测试
  8. python中select模块_基于python select.select模块通信的实例讲解 如何用python写个串口通信的程序...
  9. 详解Oracle数据货场中三种优化:分区、维度和物化视图
  10. 《css权威指南》重点摘要
  11. java pingfang,PingFang sc字体的使用
  12. 生成base64二维码带logo
  13. c语言程序32位,turbo c语言下载
  14. 一个优秀程序员必备的软件背景/桌面壁纸/集原美/鬼刀.....
  15. 我对数据分析的几点感悟
  16. Python 自动刷新网页
  17. Windows 7操作系统
  18. 实例详解ISA防火墙策略元素:ISA2006系列之五
  19. 无法删除文件 数据错误 循环冗余检查
  20. 用pip安装指定版本的包遇到的坑

热门文章

  1. 用jenkins创建节点
  2. poj 3071 Football
  3. background-size在IE8不兼容问题
  4. 关于在smarty中实现省市区三级联动
  5. git如何解决冲突(代码托管在coding)
  6. mysql 关键词相关度排序方法详细示例分析
  7. could not build module ‘Foundation’, could not build module ‘UIKit’……23个错误
  8. DreamWeaver使用技巧学习心得
  9. .NET:如何让线程支持超时?
  10. 《离散数学》双语专业词汇表 名词术语中英文索引