JavaScript百炼成仙 函数七重关之三(参数传递)

“所谓的参数,就是当函数调用的时候会传进来的值,也就是说,我们在定义参数的时候,并不知道调用的过程中会有什么样的值传过来。”接着,叶小凡随手打出一段绚丽的代码流。

function add(a,b,c){

        var sum = a + b + c;

        console.log(sum);

}

add(1,2,3);

代码运行,结果是6。

“这就是一个最简单的函数调用,配上参数传递的例子。一般来说呢,函数的名字定义就要让人一看就知道是什么意思。比如我这个例子中,add函数,别人一看就能够明白,哦,我这个函数的目的是做加法。调用函数的时候,传进去三个参数,分别是1,2,3,这三个参数分别对应add函数中圆括号,也就是参数列表内的a、b、c三个变量。在我定义这个函数的时候,a、b、c三个变量的变量名是随便取的,当然,能够见名知意最好。”

“在刚才的例子中,add函数的调用需要三个参数,分别是a、b、c。换句话说,如果你要调用add函数,就必须要传入三个参数,就像这样。”

add(1,2,3);

“函数的调用就是函数名字加上一对圆括号,这样就会去执行函数里面的代码体了,也就是这个部分。”

function add(a,b,c){

        var sum = a + b + c;

        console.log(sum);

}

“函数的代码体一般都是用花括号扩起来的,里面就是正常写JavaScript代码便可以了。没写完一句就要打一个分号,这是JavaScript代码的编写规范。现在我们来看一下这个函数的函数体里面都做了些什么事情,首先是第一行。”

var sum = a + b + c;

“sum是一个新定义的变量,注意了,这个变量是定义在add函数的函数体内部的,根据作用域的范围限定,这个变量是定义在函数作用域里面的,函数作用域是一个相对封闭的空间,也就是说,外面的全局作用域是没有办法直接访问函数作用域里面的这个sum变量的。所以说,这个sum变量只能在这个函数的函数体内被访问到,它也被叫做局部变量。好,继续看,接下来就是一个简单的加法和赋值了。从代码的字面上也可以看出来,就是把a、b、c三个变量相加之后得到一个总量,然后把这个总量用等号(赋值运算符)赋给局部变量sum的。下面一句是一个打印语句,就是把sum变量在控制台上打印出来罢了。'”

“那如果我在调用函数的时候,就传了一个参数咋办?”对面弟子问到。

“嗯,你说的这个问题,我想,可以把它单独拆分出来看。比如,我定义一个函数,设置了一个参数,但是传参的时候却一个参数都没有传。像这样的情况,和你的问题是类似的。”

“哦?那你说说看。”

“好的。”叶小凡想了一下,便打出一段代码。

function fun(a){

        console.log(a);

}

“这是一个简单的函数,函数名字是我随便取的,就叫它fun吧。这个函数是有设置参数的,参数名字是a,当然了,这个a到底是什么,是没有限定的,它可以是一个字符串,也可以是一个数字,甚至可以是一个对象,哪怕,是另一个函数,都可以。因为只是测试,所以我只是在这个函数的函数体中写了一条打印语句而已。接下来,我试着要去调用这个函数,而且,故意不写参数,就像这样。”

fun();

“这是一个非常古怪的例子,因为fun函数明明是要求填写一个参数的,那就是a。可是,在调用函数的时候,却偏偏没有参数传递进来。那么,这按理说是不被允许的,可是当这种情况真的发生了,会怎样呢?也就是说,没有参数传进来,那么函数中已经设置好的参数等于什么呢?试一下,便知。”叶小凡故意卖个关子,然后执行了代码。

结果显示:undefined

“没错了,结果就是undefined。其实,对于函数传参到底是怎么回事,可以把这个例子再次细分。刚才的函数中有一个参数a,那么这个参数自然也是属于函数作用域里面的,就相当于这样。”

function fun(){

        var a;

        console.log(a);

}

“为了方便理解,在关键的地方不犯糊涂。函数的参数,可以简单看成是在函数体,也就是花括号扩起来的地方,里面的第一行,定义了一个变量。因为我们并没有给这个变量赋值,所以这个局部变量就是undefined。可以这么说,任何变量在被赋予真正的值之前,在编译阶段都是undefined。或者说,任何变量,不管最终的值是什么,都曾经是undefined。这些函数的参数可以理解为一种预备变量。接下来说说正常的情况,比如我调用fun函数,传递一个参数18。那么传参的过程,就相当于是给预备变量赋值的过程。如果没有传参,那么预备变量自然还是undefined了。再回到刚开始的例子,如果我直传一个参数。”

function add(a,b,c){

        var sum = a + b + c;

        console.log(sum);

}

add(1);

“这种情况,a的值是1,b和c的值就是undefined,那么数字1和两个undefined相加会是多少呢,真是有意思的问题。结果是NaN,代表无法计算。没错,如果真的那样做,那么就是没有任何意义了。最起码,在这个函数中,那样的做法是毫无意义的。”

“好吧,那如果我多传一个参数会怎样呢?”对面弟子又来一个问题,大有一副不把叶小凡问道誓不罢休的意思。然后,令他没有想到的是,叶小凡立刻就有了回答。

“你说的这个问题,其实也可以单独拆解出来。就好比我定义了一个函数fun,没有参数,但是如果我在调用fun函数的时候,故意给它加了一个参数,会发生什么?比如,像这样。”

function fun(){

}

fun(10);

“结果是可想而知的,自然是什么都不会发生啦。再回到刚才的例子中去,就算你强行加了第四个参数,对结果自然也不会有什么影响的。”

function add(a,b,c){

        var sum = a + b + c;

        console.log(sum);

}

add(1,2,3,4);

“如果我一定要在函数里面访问到额外的参数咋办?”对面弟子一副问到你山穷水尽的气势,就连场外的某些弟子都看不下去了,心想这种问题实在是有些欺负人了。可是林元青在听到这个问题后,却不动声色地望向叶小凡,眼神中隐约流露出一份期待。

“这是可以办到的,其实所有的参数都会被装载到函数内部,一个叫做arguments的数组里面。比如这个add函数,虽然参数设置了abc三个,但是在函数的内部还维护了一个arguments数组。我可以用代码来验证。”

function add(a,b,c){

        console.log(arguments);

        var sum = a + b + c;

        console.log(sum);

}

add(1,2,3,4);

代码运行,结果是

“可以看到,你传过来四个参数,其实就放进了这个默认的arguments数组里面。换句话说,参数列表里面的a、b、c也是根据这个数组来赋值的。现在,我把代码改写一下,就看的更清楚了。”

function add(a,b,c){

        console.log(arguments);

        a = arguments[0];

        b = arguments[1];

        c = arguments[2];

        var sum = a + b + c;

        console.log(sum);

}

add(1,2,3,4);

“嗯,根据这个特性,可以完成一些有趣的功能,比如,我可以编写一个函数,参数个数任意写,实现数字的累加。说得简单一些,就比方说,我调用add函数的时候,传入3个数字,那么就进行三个数字的累加。如果传入5个数字,就进行5个数字的累加。也就是说,不管你传入多少数字,我都可以给你实现一个累加。这便是一个非常灵活的累加器了。”说完,叶小凡一遍思考,一边开始写代码。

“因为实现我并不知道会有几个参数传进来,所以干脆就不设置任何参数了。”

function add(){

}

“这样,我先假设调用add函数的时候,最起码会有一个参数传进来。那么,先用arguments数组获取一下第一个位置的元素。如果第一个位置的元素都不存在,那么就返回0。”

function add(){

        if(!arguments[0]){

        return 0;

}

}

“接下来,因为不知道究竟会有多少个参数,也就是说arguments数组的长度也许是未知的。但是,arguments既然是一个数组,那么就会有length属性,这个属性里面放的就是arguments数组的内部元素个数了。这样看来,虽然我不知道会有多少个参数传进来。但是我们在函数的函数体中却可以通过arguments数组的length属性预知未来传入参数的个数。这样的话,我就只需要做一个简单的数组循环,就可以了。然后,将所有的数据累加起来,像这样。”

function add(){

        if(!arguments[0]){

        return 0;

}

for(var i = 1;i < arguments.length;i++){

        arguments[0] = arguments[0] + arguments[i];

}

        console.log(arguments[0]);

}

add(1,2,3,4);

“这种写法的思路就是,从数组的第二个元素开始,往后所有的元素全部累加到第一个元素上去,就得到了数组中所有元素的和。当然,我也可以在函数内定义一个局部变量sum,全部累加到sum变量上,比如这样。”

function add(){

        var sum = 0;

        for(var i = 0;i < arguments.length;i++){

                sum = sum + arguments[i];

        }

        console.log(sum);

}

add(1,2,3,4);

“这样的话,数组的循环就可以从下标为0的地方开始。因为如果第一个元素都不存在,那么arguments数组的length就是0,也就是说,for循环连1次都不会进去的。函数的结果就是sum依然是0,还是符合预期。”

“最后,再说一下函数的返回值。就好像之前的例子,sum变量虽然是所有参数的总和,但是这个sum变量毕竟只是在函数的内部。根据作用域的关系,外面是没有办法访问函数作用域里面的sum变量的,可是既然这是一个累加函数,那么外面调用这个函数的目的自然就是要获取累加之后的值。因此,将局部变量sum暴露出去是非常有必要的。那么,怎么才可以实现这一点呢,方法就是用return关键字,将函数中的某一个数据返回出去。比如这样。”

function add(){

        var sum = 0;

        for(var i = 0;i < arguments.length;i++){

                sum = sum + arguments[i];

        }

return sum;

}

“把sum变量return出去,那么调用函数之后,函数就返回了一个sum出去,也就是说,函数的调用结果就成了sum变量,外面的全局作用域就可以获取函数内部的数据了。比如这样。”

var sum = add(1,2,3);

console.log(sum);

“这便是函数七重关之第三重关了。”听完叶小凡的讲述,就连林元青也点了点头,表示认同,对面弟子也再也挑不出刺来了。

猜你喜欢

转载自blog.csdn.net/weixin_39570751/article/details/120960378