通过实例了解js函数中参数的传递


Posted in Javascript onJune 15, 2019

先看一道JS的笔试题:

var setObj=function(o){
o.name="xiaoming";
o={};
o.name="xiaohong";
}
var p={name:"xixi",age:24};
setObj(p);
console.log(p);

答案是{name:xiaoming,age24};

在JavaScript中函数参数默认为引用类型。

一.函数传递值类型:

代码实例如下:

function addNum(num){
 num+=10;
 return num;
}
var num=10;
var result=addNum(num);
console.log(num);
console.log(result);

以上代码的弹出值分别为:10和20,下面进行一下分析:

声明变量num并复制为10,这个是num是一个值类型,当为函数传递参数的时候,是将此值复制一份传递给函数,所以在函数执行之后,num本身的值并没有被改变,函数中被改变的值仅仅是一个副本而已。

二.函数传递引用类型:

function setName(obj){ 
obj.name="青岛新锐"; 
} 
var web=new Object(); 
web.name="蚂蚁部落";
 setName(web); 
console.log(web.name);

以上代码的弹出值是:“青岛新锐”,下面进行一下分析:

声明一个对象web,它是一个引用类型,当为函数传递参数的时候,是传递的web对象的引用,也就是此对象的内存地址,所以在函数中修改属性的对象就是函数外面创建的对象本身。

三.加深理解:

function setName(obj){ 
 obj.name="青岛新锐"; 
 obj=new Object(); 
 obj.name="蚂蚁部落"; 
 } 
 var web=new Object(); 
setName(web); 
console.log(web.name);

以上代码的弹出值是:青岛新锐,很多人可能会以为将会弹出“蚂蚁部落”,下面进行一下简单的分析:

在函数外面创建一个对象,并将对象的引用赋值给变量web,web中存储的是对象在内存中的存储地址,当为函数传递参数的,就是传递的在函数外面创建的对象的地址。在函数中,为外面创建的对象创建一个自定义属性name并赋值为“青岛新锐”,然后又创建一个新的对象,并将新对象的地址赋值给obj,这个时候obj指向的并不是函数外面创建的对象,所以外面对象name属性不会被改变。

这样写对于其他语言的程序员来说是很难接受的,我们在实际的开发中避免这样的写法,因为这样会造成全局作用域污染。最近在读《javascript高级程序设计》时碰到了js传递方式的问题,花费了些时间,不过总算明白了。

数据类型

在 javascript 中数据类型可以分为两类:

  • 基本类型值 primitive type,比如Undefined,Null,Boolean,Number,String。
  • 引用类型值,也就是对象类型 Object type,比如Object,Array,Function,Date等。

变量的复制

众所周知,js中变量的基本类型和引用类型保存方式是不同的,这也就导致变量复制时也就不同了。如果从一个变量向另一个变量复制基本类型的值时,会将前者的值克隆一个,然后将克隆的值赋值到后者,因此这两个值是完全独立的,只是他们的value相同而已。

var num1 = 10;
var num2 = num1;
console.log(num2);//10

上面的num1中被保存的值为10,当把num1的值赋值给num2时,num2的值也为10。但是这两个10是完全独立的,num2中的10只是被克隆出来的,相当于我写了一个word文档,把它放到了num1的文件夹中,然后我再复制这个word文档,就叫word副本吧,然后把这个副本放到num2的文件夹下,这两个word文档是完全一样的,修改任何一个都不会影响两一个。

num2 += 1;
console.log(num1); //10
console.log(num2); //11

从上面可以看出修改num2的值,num1的值未发生变化。再来看下引用类型的复制。当从一个变量向另一个变量复制引用类型的值时,同样也会将存储在变量对象中的值复制一份放到为新变量分配的空间中。

var obj1 = {
name : "111"
};
var obj2 = obj1;
console.log(obj2.name); //111
obj2.name = "222";
console.log(obj1.name); //222

第一次打印出的结果为“111”,这个我们很容易理解,但是第二次打印出来的是“222”,有点莫名其妙了。这就是引用类型和基本类型的不同之处了。复制对象时并不会在堆内存中新生成一个一模一样的对象,只是多了一个保存指向这个对象指针的变量罢了。将obj1的值复制给obj2,而这个值的副本实际上是一个指针,这个指针指向存储在堆中的一个对象,也就是说创建了一个新的内存地址传给了obj2,obj1和obj2两个变量同时指向了同一个Object,当去改变这个对象时,他们的值都会改变,也就是说他们中任何一个作出的改变都会反映在另一个身上。下面的简易图可能更明了些。

通过实例了解js函数中参数的传递

函数参数的传递

《js高级程序设计》上是这样叙述参数传递的:所有函数的参数都是按值传递的,也就是说把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。所以如果能理解变量的复制,那么参数的传递也就很简单了。还是先从基本类型举例说明吧。

var count = 10;
function num(num1){
num1 = 1;
return num1;
}
var result = num(count1);
console.log(result);//1
console.log(count);//10,并未变成1

这个例子很容易理解,实际就是创建了一个count的副本,然后把count的值传入参数中,因为函数中定义了参数的值,所以1就将10覆盖了,最后的result返回1,而count并未发生变化。看一个有关传递对象的例子。

var person = {
name : "Tom"
};
function obj(peo){
peo.name = "Jerry";
return peo;
}
var result = obj(person);
console.log(result.name);// Jerry
console.log(person.name);// Jerry

在上面的例子中,把person复制传入obj()中,peo和person指向了同一个对象,而在peo中修改了name属性,其实修改了它们共同指向的对象的name属性,相对应的外部person所引用的name属性也就改变了,所以打印出来的为Jerry。其实这个乍一看,感觉引用类型的参数是按照引用传递的,这就是我最初犯得错误。再来看一个例子。

var person = {
name : "Tom"
}; 
function obj(peo){
peo = {
name : "Jerry"
};
return peo;
}
var result = obj(person);
console.log(result.name);// Jerry
console.log(person.name);// Tom

上面的例子中,在函数中重新定义了一个对象,也就是现在堆内存中有两个对象,外部的person指向的是老的对象,被传入参数后指向的是新定义的对象,所以调用后返回的值是新定义的对象的值。如果是参数是按引用传递的,那么person.name打印出来的结果为Jerry,从这点可以得出参数是按值传递的(有的地方叫做按共享传递)。

我们拿老罗推荐的《人类简史》把它形象化,描述的不太好。简史的第一章标题是“认知革命”,我们把它名字改为“person”根据后面的页码数可以直接找到“认知革命”的内容“也就是peoson所指向的对象”,第二章是“农业革命”,我们把它为“result”,其分目录有一节“记忆过载”(改名为“peo”),同样可以直接根据页码找到这一节内容。

现在我们把“person”复制到“peo”中,第二章中的“peo”这一节就变成了“person”,而我们根据第一章中的“peoson”找到的还是第一章的内容,这是因为它们指向了不同的内容板块,互不干扰。在这里,堆内存就是每章的内容,而第一章和第二章内容是2个不同的对象,而这两者互不相干,因此打印外部person.name时,结果仍是以前的对象的属性值。

结论

总而言之,在js中参数都是按值传递的。我写例子粗糙了些,《javascript高级程序设计》中的例子描述的更清晰一些,更易理解。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript 学习点滴记录
Apr 24 Javascript
神奇的7个jQuery 3D插件整理
Jan 06 Javascript
表单切换,用回车键替换Tab健(不支持IE)
Jul 20 Javascript
使用jQuery.fn自定义jQuery翻页插件
Jan 20 Javascript
JQuery中绑定事件(bind())和移除事件(unbind())
Feb 27 Javascript
Node.js和Express简单入门介绍
Mar 24 Javascript
Vue.js render方法使用详解
Apr 05 Javascript
JS使用正则表达式获取小括号、中括号及花括号内容的方法示例
Jun 01 Javascript
vue 实现LED数字时钟效果(开箱即用)
Dec 08 Javascript
vue从零实现一个消息通知组件的方法详解
Mar 16 Javascript
分享几个JavaScript运算符的使用技巧
Apr 24 Javascript
Javascript设计模式之原型模式详细
Oct 05 Javascript
RxJS的入门指引和初步应用
Jun 15 #Javascript
js中let能否完全替代IIFE
Jun 15 #Javascript
回顾Javascript React基础
Jun 15 #Javascript
详解微信小程序胶囊按钮返回|首页自定义导航栏功能
Jun 14 #Javascript
微信小程序版本自动更新的方法
Jun 14 #Javascript
vue+express+jwt持久化登录的方法
Jun 14 #Javascript
深入剖析JavaScript instanceof 运算符
Jun 14 #Javascript
You might like
Yii获取当前url和域名的方法
2015/06/08 PHP
学习php设计模式 php实现抽象工厂模式
2015/12/07 PHP
浅谈php和js中json的编码和解码
2016/10/24 PHP
解决php 处理 form 表单提交多个 name 属性值相同的 input 标签问题
2017/05/11 PHP
thinkphp5框架结合mysql实现微信登录和自定义分享链接与图文功能示例
2019/08/13 PHP
HTTP头隐藏PHP版本号实现过程解析
2020/12/09 PHP
简单的JS多重继承示例
2008/03/13 Javascript
基于jquery的点击链接插入链接内容的代码
2012/07/31 Javascript
jquery实现智能感知连接外网搜索
2013/05/21 Javascript
jQuery 1.9.1源码分析系列(十四)之常用jQuery工具
2015/12/02 Javascript
基于JQuery的$.ajax方法进行异步请求导致页面闪烁的解决办法
2016/05/10 Javascript
NODE.JS跨域问题的完美解决方案
2016/10/20 Javascript
javascript 内置对象及常见API详细介绍
2016/11/01 Javascript
bootstrap table复杂操作代码
2016/11/01 Javascript
自定义事件解决重复请求BUG的问题
2017/07/11 Javascript
[原创]js实现保存文本框内容为本地文件兼容IE,chrome,火狐浏览器
2018/02/14 Javascript
在Vue methods中调用filters里的过滤器实例
2018/08/30 Javascript
微信小程序实现带参数的分享功能(两种方法)
2019/05/17 Javascript
浅谈Vue3.0之前你必须知道的TypeScript实战技巧
2019/09/11 Javascript
微信小程序页面间传递数组对象方法解析
2019/11/06 Javascript
Python3实现将文件树中所有文件和子目录归档到tar压缩文件的方法
2015/05/22 Python
R语言 vs Python对比:数据分析哪家强?
2017/11/17 Python
Python 常用模块 re 使用方法详解
2019/06/06 Python
python实现美团订单推送到测试环境,提供便利操作示例
2019/08/09 Python
对Python中一维向量和一维向量转置相乘的方法详解
2019/08/26 Python
Python 使用双重循环打印图形菱形操作
2020/08/09 Python
如何让PyQt5中QWebEngineView与JavaScript交互
2020/10/21 Python
HTML5进阶段内联标签汇总(小篇)
2016/07/13 HTML / CSS
html5 初试 indexedDB(推荐)
2016/07/21 HTML / CSS
自我鉴定范文200字
2013/10/02 职场文书
消防安全宣传标语
2014/06/07 职场文书
小学运动会加油稿
2015/07/22 职场文书
学生会部长竞选稿
2015/11/19 职场文书
2016年教师节特级教师获奖感言
2015/12/09 职场文书
Mysql数据库手动及定时备份步骤
2021/11/07 MySQL
Android基础入门之dataBinding的简单使用教程
2022/06/21 Java/Android