首先我们知道, JS 当中是没有函数重载的, 在我们处理可变函数的参数的时候, 需要使用一些小技巧.
arguments
arguments 是存在于函数 (箭头函数除外) 中的一个内部变量. arguments 包含了传递给函数的参数的信息. 可以通过 arguments[0] 访问函数的第一个参数, arguments[1]访问函数的第二个函数, 以此类推. 即便如此, arguments 并不是一个数组对象, 它仅仅是只能访问索引和有 length 属性. 我们可以将 arguments 转化为真正的数组:
- var args = Array.prototype.slice.call(arguments);
- var args = [].slice.call(arguments);
- var args = Array.from(arguments);
- var args = [...arguments];
arguments 会存在引擎的优化问题, 在后续的操作技巧中, 我们不会使用 arguments 对象, 而使用 ES6 的语法代替.
不定参数
定义函数 function func([params][,...args]). 表示可以该函数可以接收不定长度的参数.
- function func(...args) {
- // 解构赋值
- console.log(`arguments: ${args}`); // args 是数组
- let [params1, params2, ...paramsRest] = args; // 拿到传入第一个参数 params1 和第二个参数 params2 和剩余参数的数组 paramsRest
- }
现在我们来实现一个函数, 它会在内部调用另外一个函数.
- const foo = (params1, params2, params3) => {
- return params1 + params2 + params3;
- };
- // 我们不需要知道 foo 的形参列表. 使用解构操作任意的形参列表.
- const func = (...args) => {
- foo(...args); // 函数调用时候展开
- foo.call(null, ...args); // 使用 call 改变 this 的值.
- foo.apply(null, args); // apply 可以直接接收参数数组
- };
同理, 部分参数确定, 部分参数可变的写法:
- function func(params1, ...args) {
- console.log(`arguments: ${args}`); // 剩余参数的数组
- }
按照 node.JS 中的习惯, callback 一般是作为最后一个参数, 如果中间参数是不定的话, 此时需要通过 typeof 判断:
- // 判断参数
- function func(err, params1, params2, callback) {
- if (typeof params1 === 'function') {
- callback = params1;
- params1 = null;
- params2 = null;
- } else if (typeof params2 === 'function') {
- callback = params2;
- params1 = null;
- } else if (typeof callback !== 'function') {
- throw new Error('参数错误');
- }
- }
- // 一些小伎俩
- function func(err, ...args) {
- // 回调函数是数组 args 的最后一项
- const callback = typeof args[args.length - 1] === 'function' ? args.pop() : null;
- const [params1 = null, params2 = null] = args;
- }
原生 JS 中, 有些函数是能同时接收 参数列表或参数数组作为参数的, 比如说 concat. 我们也可以利用 concat 的这一特性编写这样的函数:
- const func = (...args) => {
- const params = [].concat(...args); // 利用 concat 能同时接受多个参数或单个数组的特性
- console.log(params);
- };
默认参数
最基本的语法
- function func(a, b = 0) {
- return a + b;
- }
- func(5); // b 默认为 0
结合对象解构和展开
- function func(a, { opt1 = '1', opt2 = '2' }) {
- console.log(a, opt1, opt2);
- }
- func(0, { opt1: '4' }); // 0 "4" "2"
- func(0); // 错误! 因为第二参数没定义
- function func1(a, { opt1 = '1', opt2 = '2' } = {}) {
- console.log(a, opt1, opt2);
- }
- func1(0); // 可以正确运行 0 "1" "2"
也可以在函数内部进行处理
- function func(a, opts) {
- opts = Object.assign(
- {
- opt1: '1',
- },
- opts
- ); // 使用 Object.assign 赋予默认值
- opts = {
- opt1: '1',
- ...opts,
- }; // 和 Object.assign 类似
- const { opts1 = '1', opts2 = '2' } = opts; // 解构赋值, 给予默认值.
- }
错误处理
结合默认参数的语法, 我们可以实现一些错误检测, 比如说要求参数是必须传入的:
- function mandatory() {
- throw new Error('Missing parameter');
- }
- function foo(mustBeProvided = mandatory()) {
- return mustBeProvided;
- }
- foo(); // Error: Missing parameter
检查参数最大长度
- function func(x, y, ...extra) {
- if (extra.length> 0) {
- throw new Error();
- }
- }
来源: https://juejin.im/post/5bc7fe7a51882578172f3570