最近遇到个有趣的问题:“JS中的值是按值传递,还是按引用传递呢?”

在分析这个问题之前,我们需了解什么是按值传递(call by value),什么是按引用传递(call by reference)。在计算机科学里,这个部分叫求值策略(Evaluation Strategy)。它决定变量之间、函数调用时实参和形参之间值是如何传递的。

按值传递 VS. 按引用传递

按值传递(call by value)是最常用的求值策略:函数的形参是被调用时所传实参的副本。修改形参的值并不会影响实参。

按引用传递(call by reference)时,函数的形参接收实参的隐式引用,而不再是副本。这意味着函数形参的值如果被修改,实参也会被修改。同时两者指向相同的值。

按引用传递会使函数调用的追踪更加困难,有时也会引起一些微妙的BUG。

按值传递由于每次都需要克隆副本,对一些复杂类型,性能较低。两种传值方式都有各自的问题。

探究JS值的传递方式

JS的基本类型,是按值传递的。

var a = 1;
function foo(x) {x = 2;
}
foo(a);
console.log(a); // 仍为1, 未受x = 2赋值所影响

再来看对象:


var obj = {x : 1};
function foo(o) {o.x = 3;
}
foo(obj);
console.log(obj.x); // 3, 被修改了!

说明o和obj是同一个对象,o不是obj的副本。所以不是按值传递。 但这样是否说明JS的对象是按引用传递的呢?

我们再看下面的例子:

var obj = {x : 1};
function foo(o) {o = 100;
}
foo(obj);
console.log(obj.x); // 仍然是1, obj并未被修改为100.

如果是按引用传递,修改形参o的值,应该影响到实参才对。但这里修改o的值并未影响obj。 因此JS中的对象并不是按引用传递。那么究竟对象的值在JS中如何传递的呢?

按共享传递 call by sharing

准确的说,JS中的基本类型按值传递,对象类型按共享传递的(call by sharing,也叫按对象传递、按对象共享传递)。最早由Barbara Liskov. 在1974年的GLU语言中提出。该求值策略被用于Python、Java、Ruby、JS等多种语言。

该策略的重点是:调用函数传参时,函数接受对象实参引用的副本(既不是按值传递的对象副本,也不是按引用传递的隐式引用)。 它和按引用传递的不同在于:在共享传递中对函数形参的赋值,不会影响实参的值。如下面例子中,不可以通过修改形参o的值,来修改obj的值。

var obj = {x : 1};
function foo(o) {o = 100;
}
foo(obj);
console.log(obj.x); // 仍然是1, obj并未被修改为100.

然而,虽然引用是副本,引用的对象是相同的。它们共享相同的对象,所以修改形参对象的属性值,也会影响到实参的属性值。

var obj = {x : 1};
function foo(o) {o.x = 3;
}
foo(obj);
console.log(obj.x); // 3, 被修改了!

对于对象类型,由于对象是可变(mutable)的,修改对象本身会影响到共享这个对象的引用和引用副本。而对于基本类型,由于它们都是不可变的(immutable),按共享传递与按值传递(call by value)没有任何区别,所以说JS基本类型既符合按值传递,也符合按共享传递。

var a = 1; // 1是number类型,不可变 var b = a; b = 6;

据按共享传递的求值策略,a和b是两个不同的引用(b是a的引用副本),但引用相同的值。由于这里的基本类型数字1不可变,所以这里说按值传递、按共享传递没有任何区别。

基本类型的不可变(immutable)性质

基本类型是不可变的(immutable),只有对象是可变的(mutable). 例如数字值100, 布尔值true, false,修改这些值(例如把1变成3, 把true变成100)并没有什么意义。比较容易误解的,是JS中的string。有时我们会尝试“改变”字符串的内容,但在JS中,任何看似对string值的”修改”操作,实际都是创建新的string值。

var str = "abc";
str[0]; // "a"
str[0] = "d";
str; // 仍然是"abc";赋值是无效的。没有任何办法修改字符串的内容

而对象就不一样了,对象是可变的。

var obj = {x : 0};
obj.x = 100;
var o = obj;
o.x = 1;
obj.x; // 1, 被修改
o = true;
obj.x; // 1, 不会因o = true改变

这里定义变量obj,值是object,然后设置obj.x属性的值为100。而后定义另一个变量o,值仍然是这个object对象,此时obj和o两个变量的值指向同一个对象(共享同一个对象的引用)。所以修改对象的内容,对obj和o都有影响。但对象并非按引用传递,通过o = true修改了o的值,不会影响obj。

JS中的值是按值传递,还是按引用传递呢?相关推荐

  1. Thymeleaf读取model里面的对象||Thymeleaf读取model里面的集合||Themeleaf在js中取值||访问带参数的消息||ThymeleafObjects的使用[取三大作域的值

    Thymeleaf读取model里面的对象 Student.java package com.sxt.domain;import lombok.AllArgsConstructor; import l ...

  2. 微信小程序获取并修改app.js中的值

    app.js globalData: {pageSize:1,sort:"rand",pageNum:1}, 在使用页面的js中 const app = getApp()获取值va ...

  3. js中判断值不等于undefined

    文章:JS 中判断空值 undefined 和 null 转载于:https://www.cnblogs.com/Tpf386/p/9804496.html

  4. js中Boolean值为false和true的情况:

    如果逻辑对象无初始值或者其值为 0.-0.null."".false.undefined 或者 NaN,那么对象的值为 false. 否则,其值为 true(即使当自变量为字符串 ...

  5. 在js中下拉列表值的选定

    一.在做项目的时候经常要用数据库中的某个值与下拉列表里面的值(这里的值是固定写死的)相比较,然后确定选择下拉列表中的哪个值,一下是解决这个问题的一个方法: <select name=" ...

  6. 怎样用javascript给控件赋值,使在服务器端得到此控件的值?或怎样将前台的(或js)中的值传递到后台

    问: 怎样用javascript给控件赋值,使在服务器端得到此控件的值? _______________________________________________________________ ...

  7. JS是按值传递还是按引用传递?

    最近遇到个有趣的问题:"JS中的值是按值传递,还是按引用传递呢?" 在分析这个问题之前,我们需了解什么是按值传递(call by value),什么是按引用传递(call by r ...

  8. js中对于数据类型的一些理解

    Typeof的作用: 返回数据的类型 基本数据类型(Number String Boolean null undefined  es6种新增的一个基本数据symbol) Let num = 22 Ty ...

  9. js中一些常用的基本函数

    如何使用jquery刷新当前页面 下面介绍全页面刷新方法:有时候可能会用到 window.location.reload()刷新当前页面. parent.location.reload()刷新父亲对象 ...

最新文章

  1. 实测实量数据表格_施工现场全套实测实量操作图解,值得收藏!
  2. 理解卷积神经网络?看这篇论文就够了
  3. mysqlclient==1.3.7对应mysql版本_Python通过MySQLdb访问操作MySQL数据库
  4. 设计模式的理解:组合模式 (Composite)
  5. 商务智能之绩效管理 Performance Management
  6. 前端学习(2748):uniapp创建项目和演示
  7. Visual.Assist.X.V10.7.1946的汉化破解补丁
  8. 现代控制理论——状态、状态空间、状态空间描述
  9. VISIO同时选中多条线
  10. 透过现象看本质-IT程序员成长及管理
  11. 在java里四舍五入怎么做_利用java怎么实现一个四舍五入功能
  12. 不重装系统改硬盘模式: RAID ON 改成 AHCI
  13. Devcon2 (第二届全球区块链开发者峰会)演讲PPT下载
  14. PHP关闭Notice错误提示
  15. Matlab拟合工具箱的使用
  16. react按钮倒计时效果(发送验证码按钮)
  17. Nginx: 正向与反向代理
  18. SCAU华南农业大学-数电实验-用74LS283实现2*4乘法器
  19. Springboot +AOP日志系统
  20. 网络OSI七层模型学习

热门文章

  1. mysql 创建触发器出错_mysql-在phpmyadmin中创建触发器时出错
  2. jdbc连接mysql驱动包_jdbc连接数据库驱动包
  3. python代码斜率_在Python中准确地测量代码执行时间
  4. 使用图片预览插件:vue-photo-preview
  5. Mixed Content: The page at ‘xxx‘ was loaded over HTTPS, but requested an insecure resource ‘xxx‘.
  6. Oracle 升级(10.2.0.1 -- 10.2.0.4) 包含升级包
  7. idea 添加servlet依赖_详解如何使用IntelliJ IDEA新建一个Servlet项目
  8. oracle中col 的用法,Oracle中的SUM用法讲解,
  9. python验证身份证最后一位数字代表什么_身份证号码最后一位代表什么?
  10. tornado web mysql_Tornado WEB服务器框架 Epoll-- 【Mysql数据库】