通过实例了解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 进阶篇2 CSS XML学习
Mar 14 Javascript
一行命令搞定node.js 版本升级
Jul 20 Javascript
javascript实时显示当天日期的方法
May 20 Javascript
bootstrap css样式之表单
Jan 19 Javascript
巧用canvas
Jan 21 Javascript
AngularJS表格样式简单设置方法示例
Mar 03 Javascript
详解react关于事件绑定this的四种方式
Mar 09 Javascript
解决vue无法设置滚动位置的问题
Oct 07 Javascript
Angular6 Filter实现页面搜索的示例代码
Dec 02 Javascript
Node.js Buffer模块功能及常用方法实例分析
Jan 05 Javascript
微信小程序城市选择及搜索功能的方法
Mar 22 Javascript
vue-router路由模式详解(小结)
Aug 26 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中的Base62类(适用于数值转字符串)
2013/08/12 PHP
php+mysql结合Ajax实现点赞功能完整实例
2015/01/30 PHP
php生成图片验证码的实例讲解
2015/08/03 PHP
php表单习惯用的正则表达式
2017/10/11 PHP
精通Javascript系列之数据类型 字符串
2011/06/08 Javascript
实例说明为什么不要行内使用javascript
2014/04/18 Javascript
移动手机APP手指滑动切换图片特效附源码下载
2015/11/30 Javascript
理解Javascript的call、apply
2015/12/16 Javascript
仅9张思维导图帮你轻松学习Javascript 就这么简单
2016/06/01 Javascript
JS获得多个同name 的input输入框的值的实现方法
2017/01/09 Javascript
微信小程序 开发经验整理
2017/02/15 Javascript
js实现彩色条纹滚动条效果
2017/03/15 Javascript
用angular实现多选按钮的全选与反选实例代码
2017/05/23 Javascript
JavaScript中的一些隐式转换和总结(推荐)
2017/12/22 Javascript
详解Angular调试技巧之报错404(not found)
2018/01/31 Javascript
webpack 模块热替换原理
2018/04/09 Javascript
vue中的数据绑定原理的实现
2018/07/02 Javascript
小程序跳转H5页面的方法步骤
2020/03/06 Javascript
在vue-cli创建的项目中使用sass操作
2020/08/10 Javascript
[01:20]DOTA2 齐天大圣至宝动态展示
2016/12/13 DOTA
Windows和Linux下使用Python访问SqlServer的方法介绍
2015/03/10 Python
Python中splitlines()方法的使用简介
2015/05/20 Python
python爬虫的工作原理
2017/03/05 Python
《与孩子一起学编程》python自测题
2018/05/27 Python
python防止随意修改类属性的实现方法
2019/08/21 Python
python使用numpy实现直方图反向投影示例
2020/01/17 Python
美国领先的精品家居照明和装饰产品在线零售商:LightsOnline.com
2018/01/23 全球购物
CHARLES & KEITH英国官网:新加坡时尚品牌
2018/07/04 全球购物
护理专科毕业生自荐书范文
2014/02/19 职场文书
中共广东省委常委会党的群众路线教育实践活动整改方案
2014/09/23 职场文书
先进单位事迹材料
2014/12/25 职场文书
幼儿园欢迎词范文
2015/01/26 职场文书
师德培训心得体会2016
2016/01/09 职场文书
2019年亲子运动会口号
2019/10/11 职场文书
Nginx 502 Bad Gateway错误原因及解决方案
2021/03/31 Servers
ES6 解构赋值的原理及运用
2021/05/25 Javascript