JS是按值传递还是按引用传递


Posted in Javascript onJanuary 30, 2015

按值传递 VS. 按引用传递

按值传递(call by value)是最常用的求值策略:函数的形参是被调用时所传实参的副本。修改形参的值并不会影响实参。
 
按引用传递(call by reference)时,函数的形参接收实参的隐式引用,而不再是副本。这意味着函数形参的值如果被修改,实参也会被修改。同时两者指向相同的值。
 
按引用传递会使函数调用的追踪更加困难,有时也会引起一些微妙的BUG。
 
按值传递由于每次都需要克隆副本,对一些复杂类型,性能较低。两种传值方式都有各自的问题。
 
我们先看一个C的例子来了解按值和引用传递的区别: 

void Modify(int p, int * q)

{

    p = 27; // 按值传递 - p是实参a的副本, 只有p被修改

    *q = 27; // q是b的引用,q和b都被修改

}

int main()

{

    int a = 1;

    int b = 1;

    Modify(a, &b);   // a 按值传递, b 按引用传递,

                     // a 未变化, b 改变了

    return(0);

}

这里我们可以看到:
 
a => p按值传递时,修改形参p的值并不影响实参a,p只是a的副本。
b => q是按引用传递,修改形参q的值时也影响到了实参b的值。
探究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 : 1};

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。

Javascript 相关文章推荐
用JS实现一个页面多个css样式实现
May 29 Javascript
extjs grid设置某列背景颜色和字体颜色的实现方法
Sep 06 Javascript
初窥JQuery(一)jquery选择符 必备知识点
Nov 25 Javascript
Checbox的操作含已选、未选及判断代码
Nov 07 Javascript
通过JS判断联网类型和连接状态的实现代码
Apr 01 Javascript
前端js文件合并的三种方式推荐
May 19 Javascript
轻松掌握JavaScript单例模式
Aug 25 Javascript
基于JavaScript实现拖动滑块效果
Feb 16 Javascript
vue2.0 中#$emit,$on的使用详解
Jun 07 Javascript
vue2.0 自定义 饼状图 (Echarts)组件的方法
Mar 02 Javascript
React精髓!一篇全概括小结(急速)
May 23 Javascript
Vue中foreach数组与js中遍历数组的写法说明
Jun 05 Vue.js
js实现鼠标悬浮给图片加边框的方法
Jan 30 #Javascript
js控制输入框获得和失去焦点时状态显示的方法
Jan 30 #Javascript
使用mouse事件实现简单的鼠标经过特效
Jan 30 #Javascript
js实现屏幕自适应局部代码分享
Jan 30 #Javascript
jQuery弹出框代码封装DialogHelper
Jan 30 #Javascript
jquery中animate的stop()方法作用实例分析
Jan 30 #Javascript
javascript中sort()的用法实例分析
Jan 30 #Javascript
You might like
PHP中array_map与array_column之间的关系分析
2014/08/19 PHP
PHP浮点比较大小的方法
2016/02/14 PHP
Document 对象的常用方法
2009/07/31 Javascript
一个javascript图片阅览组件
2010/11/09 Javascript
js离开或刷新页面检测(且兼容FF,IE,Chrome)
2014/03/05 Javascript
cookie的secure属性详解
2015/04/08 Javascript
在easyUI开发中,出现jquery.easyui.min.js函数库问题的解决办法
2015/09/11 Javascript
JS实现的倒计时效果实例(2则实例)
2015/12/23 Javascript
JavaScript 计算笛卡尔积实例详解
2016/12/02 Javascript
jQuery常见的选择器及用法介绍
2016/12/20 Javascript
vue如何引用其他组件(css和js)
2017/04/13 Javascript
利用babel将es6语法转es5的简单示例
2017/12/01 Javascript
NodeJS安装图文教程
2018/04/19 NodeJs
JS实现根据详细地址获取经纬度功能示例
2019/04/16 Javascript
Vue中axios的封装(报错、鉴权、跳转、拦截、提示)
2019/08/20 Javascript
vue下canvas裁剪图片实例讲解
2020/04/16 Javascript
Vue 防止短时间内连续点击后多次触发请求的操作
2020/11/11 Javascript
[00:37]2016完美“圣”典风云人物:AMS宣传片
2016/12/06 DOTA
python在linux系统下获取系统内存使用情况的方法
2015/05/11 Python
Python标准库之collections包的使用教程
2017/04/27 Python
ubuntu系统下使用pm2设置nodejs开机自启动的方法
2018/05/12 NodeJs
利用Python写一个爬妹子的爬虫
2018/06/08 Python
python 对key为时间的dict排序方法
2018/10/17 Python
python 利用pandas将arff文件转csv文件的方法
2019/02/12 Python
利用pyuic5将ui文件转换为py文件的方法
2019/06/19 Python
在vscode中配置python环境过程解析
2019/09/28 Python
浅析python内置模块collections
2019/11/15 Python
关于Python 解决Python3.9 pandas.read_excel(‘xxx.xlsx‘)报错的问题
2020/11/28 Python
CSS3新属性transition-property transform box-shadow实例学习
2013/06/06 HTML / CSS
FOREO官方网站:LUNA露娜洁面仪
2016/11/28 全球购物
全球最大的瓷器、水晶和银器零售商:Replacements
2020/06/15 全球购物
模范教师材料大全
2014/12/16 职场文书
工厂仓库管理员岗位职责
2015/04/09 职场文书
go:垃圾回收GC触发条件详解
2021/04/24 Golang
漫画「狩龙人拉格纳」公开TV动画预告图
2022/03/22 日漫
MySQL数据库查询之多表查询总结
2022/08/05 MySQL