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呢?
最新文章
- [IOS 开发]TableView如何刷新指定的cell 或section
- Saddest&#39;s polar bear Pizza offered new YorkShire home
- codeforces 630KIndivisibility(容斥原理)
- ubuntu12.10可用更新源
- HttpServlet请求重定向
- HTML总结1
- JavaScript基础(一)
- POJ1789 Truck History 【最小生成树Prim】
- Easyui布局
- java自旋锁
- 用IFeatureWorkspaceAnno.CreateAnnotationClass 创建注记图层时报“The application is not licensed to modify or create schema”的错误的解决方案。
- webpack----webpack4尝鲜
- 【原创】Java基础之Session机制
- luogu P4183 [USACO18JAN]Cow at Large P
- 洛谷 P4515 [COCI2009-2010#6] XOR
- php 的 PHPExcel1.8.0 使用教程
- 域名(Domain Name)
- OpenCV颜色转换和皮肤检测
- 【Mac】安装 tesserocr 遇到的一些坑(‘cinttypes&#39; file not found)
- SQL Server 错误(待补充)
热门文章
- MyEclipse10+Jdk1.7+OSGI+MySql实现CRUD数据库
- 使用CAShapeLayer来实现圆形图片加载动画[译]
- IAR之工程配置
- ZOJ 2967 Colorful Rainbows 【Stack】
- USACO Cow Pedigrees 【Dp】
- 基于visual Studio2013解决算法导论之046广度优先搜索
- 一步一步重写 CodeIgniter 框架 (7) —— Controller执行时将 Model获得的数据传入View中,实现MVC
- java生产者消费者问题代码分析
- Android性能检测--traceview工具各个参数的意思
- C 语言学习 之搭建环境和熟悉命令