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 = ...
随机推荐
- 【Tomcat】本地域名访问设置
原路径:localhost:8080/tidyko 1.去掉8080端口 打开%TOMCAT_HOME%/conf/server.xml 修改里面的 <Connector connectionT ...
- CentOS 6 用SVN自动提交文件到web服务器
关于 svn 的安装 参考:[转]Linux(centOS6.5)下SVN的安装.配置及开机启动 经过两天的各种尝试总算解决了,总结如下: 1.在建立库时注意 要让库的名称和 要同步的 web目录名 ...
- bresenham算法的FPGA的实现2
在上一篇里http://www.cnblogs.com/sepeng/p/4045593.html <bresenham算法的FPGA的实现1>已经做了一个整体框架的布局,但是那个程序只是 ...
- JS 切换显示
<style> #hhh div { width:200px; height:200px; background:red; display:none; ...
- Python文本处理(1)
每次处理一个字符 解决方法: 创建列表 thestring='abcdefg' thelist=list(thestring) print thelist 结果 ['a', 'b', 'c', 'd' ...
- 无线网络wifi (WPA/WPA2)密码破解方法
无线网络password破解WPA/WPA2教程 本教程用于探索无线路由安全漏洞,禁止用于非法用途,违者法律必究(与我无关) 在动手破解WPA/WPA2前,应该先了解一下基础知识,本文适合新手阅读 首 ...
- Linux高性能server编程——Linux网络基础API及应用
Linux网络编程基础API 具体介绍了socket地址意义极其API,在介绍数据读写API部分引入一个有关带外数据发送和接收的程序,最后还介绍了其它一些辅助API. socket地址API 主 ...
- Web 应用程序项目 XXXX 已配置为使用 IIS。 无法访问 IIS 元数据库。您没有足够的特权访问计算机上的 IIS 网站。(转载)
Web 应用程序项目 XXXX 已配置为使用 IIS. 无法访问 IIS 元数据库.您没有足够的特权访问计算机上的 IIS 网站. 2012年05月19日 ⁄ 综合 ⁄ 共 261字 ⁄ 字号 小 中 ...
- 修改linux文件权限命令:chmod 【转载】
Linux系统中的每个文件和目录都有访问许可权限,用它来确定谁可以通过何种方式对文件和目录进行访问和操作. chmod 命令可以改变所有子目录的权限,下面有2种方法 改变一个文件的权限: chmod ...
- java多线程中synchronized关键字的用法
转自:http://www.cdtarena.com/javapx/201308/9596.html 由于同一进程内的多个线程共享内存空间,在Java中,就是共享实例,当多个线程试图同时修改某个实例的 ...