这个章节要来介绍参数
前几篇的文章对参数有一些介绍,这篇文章会对参数的各种状态进行更详细的介绍。
在介绍参数之前,一个函式在运行之前,会带入那些参数。
var globalVariables = '全域变数';var obj = { afunction: function (para) { var localVariables = '区域变数'; console.log(para, localVariables, arguments, this, globalVariables); }};// 执行obj.afunction('一段描述', 2, 3);
我们可以看到,这段程式码在执行的时候带入的参数是3个,但接受的 function 只有 para 一个参数,也就是说,para 这个参数只会对应到 一段描述 这个字串,其他的2、3没有传进去。
看一下执行的结果~
我们可以看到 globalVariables 以及 localVariables都有对应到正确的值,而全域变数之前的章节也有讨论过,如果找不到就会向外寻找直到找到为止,不然就回传 not defined。
this的部分后面会再详细的讨论,这里就先跳过。
重点是又多了一个 arguments 的变数,而且他好像是一个阵列,装着'一段描述', 2, 3 的三个值。
但其实这个 arguments 被称作 类阵列 ,但其实他不是阵列。虽然它可以被 for 迴圈处理内部的资料,但对于大部分阵列操作的指令他都无法执行。
Hoisting 影响参数的运行
function callName (a) { console.log(a); // 小明}callName('小明');
上述执行的结果应该很明显就是小明没有甚么好讲的对吧~
那么如果改成下面这样呢?
function callName (a) { console.log(a); // 小明 var a; console.log(a); // 小明}callName('小明');
其实执行起来也还是小明喔!
原因是因为,我们再宣告一个变数的时候,这个变数名称已经存在的时候,这个宣告就是无效的。
所以 var a;
是无效的,自然 a 就还是保持在小明的状态。
那接下来我们把 a 改成 杰伦 呢?
function callName (a) { console.log(a); // 小明 var a; console.log(a); // 小明 a = '杰伦'; console.log(a); // 杰伦}callName('小明');
这时候就会是杰伦了,所以要改变内部的参数,直接覆盖就可以了!
那么重头戏来了喔~!
如果我今天在里面定义的是 函式陈述式呢?
根据之前学过的观念是,函式陈述式会最早被写入在记忆体空间中。
我们来实际操作看看
function callName (a) { console.log(a); function a () {} var a; console.log(a); a = '杰伦'; console.log(a); }callName('小明');
很明显在 a 还没被杰伦覆盖之前,传入的小明就被 函式陈述式 给附盖了。
所以虽然 函式陈述式 会最早被写入在记忆体空间中,但最早是指在这个函式内的 {}
的最早。
因此 函式陈述式 并不会比 '小明' 这个参数还早,所以显示的结果才是 函式陈述式。
定义的参数名称的规则
我们再定义函式接收的参数名称的时候,注意的只有参数的数量,参数的名称都是可以自定义的,只要不要重複就好。
我们接下来来看看下面的例子:
function callMore (d,c,b,a){ console.log(d,c,b,a);}var a = 'a';var b = 'b';var c = 'c';callMore(a, b ,c);
目前虽然传了3个参数进去,但函式接受的参数定义是4个,因此最后一个 a 就会在函式内被定义为 undefined。
传入参数是物件类型的资料,依然会维持传参考的特性
看一下範例吧~!
function callObject (obj) { obj.name = '杰伦家';}var family = { name: '小明家'}callObject(family);console.log(family);
所以这边执行后的结果很明显就是 family.name 会被改成 杰伦家。
这边也要提醒一下,尽量避免传入物件类型的资料后,又在函是内部修改资料内容,避免不预期的结果。
当然也是有人利用这种特性进行撰写,但其实这样的撰写风格不易追蹤,维护成本也较高。
因此不太建议这么写。
CallBack Function
function FnB (fn) { fn('小明');}FnB(function (a) { console.log(a);});
这样的函式直接执行,我们就先把参数预定在 FnB
中,等到执行的时候,传入ㄧ个 function,而 function 就会接收到 FnB
中的参数,并做ㄧ些处理。
我们也可以改写成
function callSomeone (name) { console.log(name + '你好');}function FnB (fn) { fn('小明');}FnB(callSomeone);
这样的写法,我们把 callSomeone 赋予到 FnB 的参数 fn上。
我们是透过函式表达式的方式传入到 FnB 的 function 中,因此真正执行的地方是在 callSomeone 的 function 里面。
而这样呼叫的方法呢,我们又称作 callback function。
类阵列 Arguments
刚刚有说到 arguments 是一个类阵列,每个函是在运行的时候都会有,他不需要特别宣告就可以取用。
他会接受所有传进来的值,并以一个类似阵列的结构乘装着,但他不是真正的阵列。
function callArg (a) { console.log(a, arguments);}callArg(1,2,3,'a','5');
我们可以对这个 arguments 做 for 迴圈的取值动作
function callArg (a) { console.log(a, arguments); for (var i = 0; i < arguments.length; i ++) { console.log(arguments[i]); }}callArg(1,2,3,'a','5');
但我们就没办法对她使用 forEach 的方法
function callArg (a) { console.log(a, arguments); arguments.forEach(function () {});}callArg(1,2,3,'a','5');
关于甚么是类阵列,在这个章节还不需要先学习。
只要知道 arguments 是在函是运行的时候自带的变数,并且会乘装ㄧ切传入的值,这样就可以噜~
没有问题的话我们就可以往下一篇文章迈进了! 希望对各位有帮助~汪汪!