JavaScript进阶(三) 值传递和引用传递
从C语言开始
- void swap1(int a, int b);
- void swap2(int* a, int* b)
这里swap1是不能交换两个数的值的,swap2可以。那为什么呢?有教材会说,第一个是值传递,第二个是引用传递,传递的是指针,所以第二个可以。好吧,这个解释和没说一样,那下面我就来解释一下,调用这两个函数的时候,到底发生了什么,为什么一个可以交换,另一个不可以。为了方便描述,我把这两个函数的调用代码也写出来
- int main() {
- int a = 3;
- int b = 4;
- swap1(a, b); //此时a = 3, b = 4;
- int* pa = &a;
- int* pb = &b; //为了方便解释,增加这两个临时变量,否则直接写swap2(&a, &b)的话,这行代码做的事情太多,不好解释。
- swap2(pa, pb); //此时a = 4, b = 3;
- return 0;
- }
函数的执行是在栈中,下图描述了swap1执行开始和结束的时候,栈中的情况。
回到JS
- function reverse1(array) {
- var temp = [];
- for (var i = array.length - 1; i > -1; i--) {
- temp.push(array[i]);
- }
- array = temp;
- }
- function reverse2(array) {
- var temp = [];
- for (var i = array.length - 1; i > -1; i--) {
- temp.push(array[i]);
- }
- for (var i = 0; i < array.length; i++) {
- array[i] = temp[i]
- }
- }
这两个函数都是先将一个反序完成的数组存储在temp里面,然后赋值给入参array,就是赋值的方式有所不同。这个不同的赋值方式也导致了结果的不同,结果就是reverse1无法完成工作,reverse2可以。为了解答这个问题,我先讲一下JS里面,内存中对象是如何存储的。当一行代码 var temp = [] 被运行的时候,内存中是这样的:
其中蓝色的是栈,黑框的是堆,用来动态分配内存,最右绿色的表示这段堆的起始地址。也就是说当声明一个对象的时候,栈中保存的内容只是一个指针,真正的内容在堆中。以此为基础,我们再来看一下当函数reverse1执行的时候,内存中如何实现的。为方便举例,假设传入的数组为[1,2,3];
上图为执行前,下图为执行后。当函数reverse1执行时,in作为参数传入。传入参数时,类似C语言的引用传递,将地址复制了一份,压栈传到子函数中。所以两个函数中的变量是指向同一个位置的。当reverse1执行时,temp中存储了array的反序,最后一行赋值的时候,你就看到了如下面的图表示的那样,reverse1中的array确实指向了新的反序数组,但是调用者中的局部变量in却丝毫未动。所以导致了reverse1无法完成反序功能。
那么我们再看reverse2. reverse2中的第二个循环逐个给数组的内容复制,其实它操纵的内存空间就是array指向的区域,我们又知道array和in指向了同一个区域,所以in指向的区域也被改变了。
总结一下以上所说的,
- JS中布尔,数字为基本数据类型,是值传递。无法作为引用传递。所以JS中无法实现基本数据类型的swap函数。
- 对象是引用传递。当传递对象给子函数时,传递的是地址。子函数使用这个地址来操作修改传入的对象。但是如果在子函数修改该地址指向的位置时,这个改变将无法作用于调用者。
- 引用传递其实还是值传递,只是传入的值是个地址,并且该地址指向了一段保存了对象数据的内存。这点和C中的引用传递类似。
特别说一下String
- function foo(s) {
- s = "\"" + s + "\""
- }
那么正确的函数应该怎写呢?你可能会想,应该使用String对象的函数来修改String的内容。这么想是对的,但是很不幸,JS提供的String没有任何一个可以修改String内容的函数。有人说不对,比如字符串连接函数,concat,转大小写函数toUpperCase,toLowerCase。事实上这两个函数只是返回了一个新的String对象,其原本的值兵没有改动。这个你可以去做实验看看。所以String对象被建立好之后,就再也无法改动了,所以无法用一个子函数来修改它的值。又由于String可以用 == 来判断其内容是否相等,所以它的各方面特性都很像基本数据类型。但是还有一点不一样,请看下面的例子:
- var a = 1
- var b = 1
- a == b //true
- a === b //true
- var s1 = "sdf"
- var s2 = "sdf"
- s1 == s2 //true
- s1 === s2 //true
- s3 = new String("sdf")
- s1 === s3 //false
对于数字,估计各位没有疑问吧。那么对于字符串来说,== 比较的是两个字符串的内容,这个应该也没有疑问。那么===呢?并且为什么s1===s2为true,s1===s3为false呢?
JavaScript进阶(三) 值传递和引用传递的更多相关文章
- JavaScript传递变量:值传递?引用传递?
今天在看 seajs-2.2.1/src/util-events.js源码,里面有段代码不是很理解: var events = data.events = {} // Bind event seajs ...
- JavaScript 函数参数传递到底是值传递还是引用传递
tips:这篇文章是听了四脚猫的js课程后查的,深入的理解可以参看两篇博客: JavaScript数据类型--值类型和引用类型 JavaScript数据操作--原始值和引用值的操作本质 在传统的观念里 ...
- Android For JNI(三)——C的指针,指针变量,指针常见错误,值传递,引用传递,返回多个值
Android For JNI(三)--C的指针,指针变量,指针常见错误,值传递,引用传递,返回多个值 C中比较难的这一块,大概就是指针了,所以大家还是多翻阅一下资料,当然,如果只是想了解一下,看本篇 ...
- 188W+程序员关注过的问题:Java到底是值传递还是引用传递?
在逛 Stack Overflow 的时候,发现了一些访问量像阿尔卑斯山一样高的问题,比如说这个:Java 到底是值传递还是引用传递?访问量足足有 188万+,这不得了啊!说明有很多很多的程序员被这个 ...
- [转帖]Stack Overflow上188万浏览量的提问:Java 到底是值传递还是引用传递?
Stack Overflow上188万浏览量的提问:Java 到底是值传递还是引用传递? http://www.itpub.net/2019/12/03/4567/ 在逛 Stack Overfl ...
- Java中引用类型变量,对象,值类型,值传递,引用传递 区别与定义
一.Java中什么叫做引用类型变量?引用:就是按内存地址查询 比如:String s = new String();这个其实是在栈内存里分配一块内存空间为s,在堆内存里new了一个Stri ...
- 【转载】C++ 值传递、指针传递、引用传递详解
原文链接:http://www.cnblogs.com/yanlingyin/ 值传递: 形参是实参的拷贝,改变形参的值并不会影响外部实参的值.从被调用函数的角度来说,值传递是单向的(实参->形 ...
- Java面向对象-方法的值传递和引用传递
Java面向对象-方法的值传递和引用传递 0 发布时间:『 2016-08-21 14:21』 博客类别:Java核心基础 阅读(197) 评论(0) Java面向对象-方法的值传递和引用传递 方 ...
- 一道笔试题来理顺Java中的值传递和引用传递
题目如下: private static void change(StringBuffer str11, StringBuffer str12) { str12 = str11; str11 = ...
随机推荐
- DataTable的属性与使用方式
一.DataTable简介 (1)构造函数 DataTable() 不带参数初始化DataTable 类的新实例. DataTable(string t ...
- cygwin中vim的使用方法
vim类似Windows中的记事本,功能非常强大. vim的使用技巧 1.vim text.txt text存在则打开,不存在则类似新建一个叫text的txt文件 2.退出 按esc切换到命令模式,然 ...
- HDU 1969(二分法)
My birthday is coming up and traditionally I’m serving pie. Not just one pie, no, I have a number N ...
- [Swust OJ 1125]--又见GCD(数论,素数表存贮因子)
题目链接:http://acm.swust.edu.cn/problem/1125/ Time limit(ms): 1000 Memory limit(kb): 65535 Descriptio ...
- BZOJ 2809: [Apio2012]dispatching( 平衡树 + 启发式合并 )
枚举树上的每个结点做管理者, 贪心地取其子树中薪水较低的, 算出这个结点为管理者的满意度, 更新答案. 用平衡树+启发式合并, 时间复杂度为O(N log²N) ------------------- ...
- 【集训笔记】归纳与递推【HDOJ1297
例:(2050)折线分割平面 问题描述: 平面上有n条折线,问这些折线最多能将平面分割成多少块? 样例输入 1 2 样例输出 2 7 平面上有n条折线,问这些折线最多能将平面分割成多少块? 解: 折线 ...
- json_response的用法
传统的方法是当我们处理一个表单时,我们Post数据给服务器,服务器对数据进行处理后将数据返回给用户,此时部分写法是用页面刷新的方式将页面重新刷新一次呈现给用户,这样的话用户相当于读入了两次页面,人一多 ...
- Week1(9月12日):很激动的第一次课
Part I:课程介绍 =========================== 1. 学时 8*16=128 2. 时间 周二1234,周五1234 3. 地点 E307 4. 考试方式 笔试+上机 ...
- JavaScript 的数组操作--删除元素
在JavaScript中,可以很方便的删除指定位置的元素,这个是用到 splice方法, 该方法用于删除或替换数组中的部分数据. 其语法定义是 : splice(start , count [,new ...
- 跟上节奏 大数据时代十大必备IT技能
跟上节奏 大数据时代十大必备IT技能 新的想法诞生新的技术,从而造出许多新词,云计算.大数据.BYOD.社交媒体……在互联网时代,各种新词层出不穷,让人应接不暇.这些新的技术,这些新兴应用和对应的IT ...