JavaScript之函数的参数

2018-04-21  本文已影响0人  thisDong

任何编程语言中都有函数的概念,JS中也不例外,今天就来推进一点点知识点,看一看函数中的参数。这个参数啊还真是“别有风味”,和别的编程语言有不小的差异。不过总结知识之前,先来张让我激动不已的手办图片,让脑子充点血好用功学习。

战场原黑仪

激动完毕~开始学习。要说JS中的参数那简直能用“来着不拒”四个字来形容。为什么说是来着不拒呢?这就是它和其他编程语言不同的地方,JS中函数不介意传进来多少个参数,也不在乎传进来参数是什么数据类型。也就是定义的函数只接受三个参数,在调用这个函数的时候未必一定要传递三个参数,可以传进来两个,也可以是四个,或者一个都不传进来,而解析器不会有丝毫的“不爽”。

之所以会出现这种情况的原因是,JS的参数在内部使用一个数组来表示的,函数接受的始终是这个数组,而不关心数组中包含哪些参数。如果这个数组不包含任何参数,无所谓啦。如果这个数组包含多个参数,也没问题。在函数体内我们可以用arguments对象来访问这个参数数组,从而去获取传递函数的每一个参数。严格意义上来说arguments对象并不是一个数组,它只是与数组类似,因为它别不是array对象的实例。不过这不影响我们像使用数组一样的去使用arguments对象。

这样我们就有灵活的方式去实现操作参数。比如我们可以用arguments.length获取传递进来参数的数量,也可以用arguments[i]直接获取第i个参数(和数组一样i是从零开始)。

function  goData  (){
 /*arguments.length获取参数长度*/
 console.log("参数有:"  + arguments.length  +  "个。");
}

goData("girls",99);  /*参数有:2个。*/

goData();  /*参数有:0个。*/

goData(64);  /*参数有:1个。*/

上面的例子演示了如何获取传进来的参数数量,那么我们要把函数改造下。让我们的函数能“稍微”灵活的面对复杂一点的情况。

function  goData  (){

 var  sum;

 if  (arguments.length  ==  1){

 //如果只有一个参数,就让它加10

 sum  =  arguments[0]  +  10;

    }  else  if  (arguments.length  ==  2){

 //如果只有两个参数,就让它们相加

 sum  =  arguments[0]  +  arguments[1];

    }
    console.log(sum);
}

goData(10);  //20
goData(90,15);  //105。

比较有意思的地方是,arguments.length是由传入参数的个数决定的,和定义函数命名参数的个数无关。(形参和实参??)没有传递值的命名参数将自动赋值为undefined


function  goData(a,b){

 console.log(arguments[1]);

}

goData(10);  //undefined

goData(10,94);  //94

最重要的也是最需要理解的一点是,JS函数的参数都是按值传递的,并不是按引用传递的。

关于按值传递和按引用传递的知识,我们需要从变量说起。变量可能包含两种不同数据类型的值:基本数据类型值和引用数据类型值,基本数据类型值指的是简单的数据段,而引用数据类型指那些可能有多个值构成的对象。在将一个值赋给变量时,解析器必须确定这个值是基本数据类型值还是引用数据类型值。

五种基本类型:UndefinedNullBooleanNumberString。这五种是按值访问的,因此可以操作保存在变量中的实际值。引用类型的值是保存在内存中的对象。而JS中规定不允许直接访问内存中的位置,也就是不能直接操作对象的内存空间。操作对象时,可以理解为我们是在操作对象的引用而不是实际的对象,所以说应用类型的值是按照引用访问的。有点懵圈了……

我们从理解复制变量的过程去理解按值传递和按应用传递的区别,这一切都是理解“函数的参数是按值传递”这个概念的大前提……继续,复制变量的时候变量值基本类型值时的情况是:

var  one  =  90;

var  two  =  a;  //将a赋值给b
one  =  5  ;//one重新赋值5
console.log(two);  //结果还是90

变量one中保存的是“90”,当使用one初始化变量two的时候在two也保存了值“90”。但是在one和two中的“90”是相互独立的,two中的值只是one中的一个副本。这两个变量可以参与任何计算而不互相影响。如下图所示:

当变量向另一个变量复制引用类型值的时候,同样也会将储存在变量对象中的值复制一份到为新变量分配的空间中,不同的是这个值的副本其实是一个指针,而这个指针指向的是存储在堆中的一个对象。复制操作结束后,两个变量引用的是同一个对象,改变一个变量就会影响到另外一个变量。

var  object1=  new  object();
var  object2=  object1;

object1.name="妹子";
console.log(object2.name);  //也会变成"妹子"

有了这些知识储备,再回头来理解“函数的参数是按值传递”就相对容易一些。我们从一个例子来看下为什么说函数的参数是按值传递的。

function  GoToData(obj){
 obj.name  =  "黑丝妹子";  //传入的对象设置name
 obj  =  new  Object();  
 obj.name  =  "细长腿黑丝妹子";  //设置新对象的name
}

var  goodgirl  =  new  Object();

GoToData(goodgirl);  //调用函数

console.log(goodgirl.name);  //"黑丝妹子"

goodgirl和obj为同一个对象,单看前面,当在函数内部修改对象obj的时候,goodgirl对象也会相应的发生变换,这一切看上似乎是按照引用传递的,但是在函数内部重新定义变量obj为新对象的时候就直接把真相出卖了。如果函数的参数是按照引用传递的,那么在第二给对象赋值”细长腿黑丝妹子”的时候,外部的对象goodgirl也会发生相应变化,可是最终结果却是没有变化,证明了函数参数在传递过程中是按照值传递的,传递的内容是“指针”地址,而非变量的引用。

我们可以把函数的参数想象成局部变量,当函数内部重写对象obj的时候,这个变量引用的是个局部对象,局部对象在函数执行完毕后会被立即销毁。这种形式能个我们带来一定的便利同时也会给我们带来一定困惑。我们需要扬长避短,发挥长处即可。

总结完毕~ !再回想一遍知识点就睡觉去……媳妇已经开始打呼噜了/(ㄒoㄒ)/~~

(报告完毕!)

上一篇下一篇

猜你喜欢

热点阅读