通过实例了解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 相关文章推荐
用js实现预览待上传的本地图片
Mar 15 Javascript
Jquery Ajax.ashx 高效分页实现代码
Oct 20 Javascript
jquery photoFrame 图片边框美化显示插件
Jun 28 Javascript
JS+CSS实现仿msn风格选项卡效果代码
Oct 22 Javascript
原生js和jQuery实现淡入淡出轮播效果
Dec 25 Javascript
微信小程序之数据双向绑定与数据操作
May 12 Javascript
jquery 给动态生成的标签绑定事件的几种方法总结
Feb 24 jQuery
webpack4 CSS Tree Shaking的使用
Sep 03 Javascript
微信小程序实现bindtap等事件传参
Apr 08 Javascript
JS前端知识点offset,scroll,client,冒泡,事件对象的应用整理总结
Jun 27 Javascript
微信小程序自定义弹窗滚动与页面滚动冲突的解决方法
Jul 16 Javascript
node运行js获得输出的三种方式示例详解
Jul 02 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
PHP源代码数组统计count分析
2011/08/02 PHP
php生成zip压缩文件的方法详解
2013/06/09 PHP
解析zend studio中直接导入svn中的项目的方法步骤
2013/06/21 PHP
php实现用户注册密码的crypt加密
2017/06/08 PHP
PHP类与对象后期静态绑定操作实例详解
2018/12/20 PHP
xml 封装与解析(javascript和C#中)
2009/07/26 Javascript
window.open的页面如何刷新(父页面)上层页面
2012/12/28 Javascript
借助script进行Http跨域请求:JSONP实现原理及代码
2013/03/19 Javascript
jquery重复提交请求的原因浅析
2014/05/23 Javascript
jQuery实现加入购物车飞入动画效果
2015/03/14 Javascript
jQuery插件ajaxFileUpload实现异步上传文件效果
2015/04/14 Javascript
js实现鼠标移到链接文字弹出一个提示层的方法
2015/05/11 Javascript
Vue.js动态组件解析
2016/09/09 Javascript
angular 实现的输入框数字千分位及保留几位小数点功能示例
2018/06/19 Javascript
在vue项目中正确使用iconfont的方法
2018/09/28 Javascript
JS实现图片拖拽交换效果
2018/11/30 Javascript
JavaScript判断数据类型有几种方法及区别介绍
2020/09/02 Javascript
[09:13]2014DOTA2国际邀请赛 中国区预选赛coser表演
2014/05/23 DOTA
[02:07]DOTA2新英雄展现中国元素,完美“圣典”亮相央视
2016/12/19 DOTA
利用python 更新ssh 远程代码 操作远程服务器的实现代码
2018/02/08 Python
pandas DataFrame实现几列数据合并成为新的一列方法
2018/06/08 Python
Python常用特殊方法实例总结
2019/03/22 Python
Python发送邮件的实例代码讲解
2019/10/16 Python
详解html5页面 rem 布局适配方法
2018/01/12 HTML / CSS
Kent & Curwen:与大卫·贝克汉姆合作
2017/06/13 全球购物
德国汽车零件和汽车配件网上商店:kfzteile24
2018/11/14 全球购物
毕业生自荐书
2014/02/03 职场文书
乡镇信息公开实施方案
2014/03/23 职场文书
质量保证书范本
2014/04/29 职场文书
访谈节目策划方案
2014/05/15 职场文书
责任胜于能力演讲稿
2014/05/20 职场文书
教师廉洁自律承诺书
2014/05/26 职场文书
教师节领导致辞
2015/07/29 职场文书
节约用水广告语60条
2019/11/14 职场文书
浅谈MySQL user权限表
2021/06/18 MySQL
笔记本自带的win11如何跳过联网激活?
2022/04/20 数码科技