记录学习过程,如有错误欢迎指出
今天在看《Javascript语言精髓与编程实战》
时,看到周爱民老师在书中讲解的一些关于函数参数的知识,特此我结合自己的理解分享给大家
如果你熟悉某些知识点,可以跳至 非简单参数
默认参数
可以理解为函数参数的默认值,假设foo函数接收3个参数.但是我们不是必须三个参数都要传
function foo(name,age,gender='未知'){
....
}
foo('bezos',20)//bezos 20 未知
foo('bezos',20,男)bezos 20 男
相信大家现在能够理解了默认参数,默认参数可以位于参数列表的任意位置
参数个数
foo.length可以获取函数参数个数
function foo(name,age,gender='未知'){
....
}
foo.length //2
这里为什么是2呢?不应该是3吗?
因为js不会将默认参数算进参数个数
function foo(name,age,gender='未知',height){
....
}
foo.length //2
现在你应该又要问了明明只有1个默认参数,为什么length还是2呢?
因为js不会将默认参数(包括自己)之后的参数算入参数个数
注意:即便传入参数undefined,默认参数也会生效
剩余参数
剩余参数用于"一个标识符对应多个传入参数"的情况
---摘自《Javascript语言精髓与编程实战》
function foo(name,...args){
console.log(args);
}
foo('bezos',18,'男')//[ 18, '男' ]
作用就是收集所有没有被形参所匹配的参数(仅收集形参之后
未匹配的)
剩余参数和默认参数一样也不计入参数个数
前戏结束
arguments
arguments就是一个类数组对象,它包含了该函数的所有参数并且是有序
除箭头函数外的所有函数都会自动创建arguments,函数内部可以自由访问这个arguments
既然知道arguments表示所有参数,那么arguments.length是函数参数长度
也不难推出
function foo(name, age) {
console.log(arguments);
}
foo("bezos", 18);//[Arguments] { '0': 'bezos', '1': 18 }
形参和arguments的关系
首先来看两个例子
function foo(name) {
console.log(name);
arguments[0] = "bob";
console.log(name);
}
foo("bezos");
/*
bezos
bob
*/
function bar(age) {
console.log(arguments[0]);
age = 20
console.log(arguments[0]);
}
bar(18);
/*
18
20
*/
现在我们知道了它们俩的关系:
arguments和形参是相互绑定的,会互相影响
解构arguments对象后再用解构变量进行改变是不会出现绑定效果的,所以剩余参数自然也不会触发绑定
我们再深入探讨一下,基于上面的例子.我们知道了形成和arguments是相互绑定的,但是一旦将参数从arguments中解构出来,就不会触发绑定.由此我们知道了arguments仅是对当前全部参数引用,所以修改arguments就相当于在修改形参
最后我觉得arguments就是js给你的一个快速访问未被形参匹配的快捷路径,它并不是真正存在的一个类,而是形参组成的类
非简单参数(重点开始)
默认参数,剩余参数,模板参数 统称为"非简单参数"
--- 摘自《Javascript语言精髓与编程实战》
铺垫了这么多终于可以引出下文了
js函数处理调用时的实参时有两种方式:
- 用初始化赋值
- 形参与arguments绑定
js还得从这两种方式中二选一
非简单参数只能使用"用初始化赋值"
一旦使用"用初始化赋值"这种方式,那么就会导致js函数增加三个限制:
- 无法从函数内部显示开启严格模式,可以从函数外开启从而影响函数内
- 不管是否严格模式,参数声明不再接受"重名参数"
- 不管是否严格模式,
形参和arguments之间接触绑定
上述前三个限制,最主要的还是第三个.因为形参和arguments之间解除了绑定,当在使用默认参数时就会出现一种特殊情况
function foo(name = "bezos", age, gender = "未知") {
console.log(...arguments);
console.log(name, age, gender);
}
foo(undefined, 18, "男");
/*
undefined 18 男
bezos 18 男
*/
发现了没?我们在函数调用时明明参数1传的undefined,默认参数理因生效,那么为什么输出的arguments是undefined 18 男
呢?应该是1 18 男
才对呀
这就是"用初始化赋值"所带来的特殊作用
我们来梳理一下:
首先调用foo(),然后函数通过"用初始化赋值"初始参数
初始器识别到参数1传入了undefined,默认参数生效name = "bezos"
但是我们使用到了默认参数,属于非简单参数,触发了上面提到的三个限制,形成和arguments之间解绑
,所以name的引用arguments拿不到了,拿不到引用也就察觉不到name发生了变化
,还以为name是传入的undefined
最后输出undefined 18 男
非惰性求值(小知识)
思考以下输出
function foo(value) {
console.log(value);
}
let i = 0;
foo((i += 10), (i += 10));
foo(i);
最终输出为
10
20
foo接收一个参数,虽然后面的参数没有被接收,但是被执行了
,以致于第二foo输出20
这就体现了非惰性求值
所以我们在实际开发中应匹配参数个数完美,避免不必要的非惰性求值,导致浪费