rest参数语法
rest参数的基本概念
ECMAScript 6引入的rest参数语法允许我们将不定数量的参数表示为一个数组。这种语法通过在函数参数前添加三个点(...)来实现,它解决了ES5中处理可变参数时需要使用arguments对象的繁琐问题。
function sum(...numbers) {
return numbers.reduce((prev, curr) => prev + curr, 0);
}
console.log(sum(1, 2, 3)); // 输出6
console.log(sum(1, 2, 3, 4, 5)); // 输出15
rest参数与arguments对象的区别
rest参数与传统的arguments对象有几个关键区别:
- rest参数是真正的数组实例,可以直接使用数组方法
- arguments对象包含所有参数,而rest参数只包含没有对应形参的剩余参数
- rest参数必须在参数列表的最后
// 使用arguments对象
function oldWay() {
const args = Array.prototype.slice.call(arguments);
return args.join('-');
}
// 使用rest参数
function newWay(...args) {
return args.join('-');
}
console.log(oldWay('a', 'b', 'c')); // "a-b-c"
console.log(newWay('a', 'b', 'c')); // "a-b-c"
rest参数的典型应用场景
函数参数收集
rest参数最常见的用途是收集函数的多余参数:
function logWithPrefix(prefix, ...messages) {
messages.forEach(message => {
console.log(`${prefix}: ${message}`);
});
}
logWithPrefix('INFO', '系统启动', '加载配置完成', '服务已就绪');
替代apply方法
在ES5中,我们需要使用apply来将数组展开为参数,现在可以使用rest参数和扩展运算符:
// ES5方式
Math.max.apply(null, [1, 2, 3]);
// ES6方式
Math.max(...[1, 2, 3]);
// 结合rest参数
function wrapper(...args) {
return Math.max(...args);
}
解构赋值中的rest参数
rest参数语法也可以用于解构赋值:
const [first, second, ...rest] = [1, 2, 3, 4, 5];
console.log(first); // 1
console.log(second); // 2
console.log(rest); // [3, 4, 5]
const {a, b, ...others} = {a: 1, b: 2, c: 3, d: 4};
console.log(a); // 1
console.log(b); // 2
console.log(others); // {c: 3, d: 4}
rest参数的注意事项
- rest参数必须是函数的最后一个参数:
// 错误示例
function invalid(a, ...b, c) {
// SyntaxError: Rest parameter must be last formal parameter
}
- rest参数不计入函数的length属性:
function func1(a, b) {}
function func2(a, b, ...c) {}
console.log(func1.length); // 2
console.log(func2.length); // 2
- 箭头函数也可以使用rest参数:
const sum = (...nums) => nums.reduce((a, b) => a + b, 0);
rest参数的高级用法
类型检查和参数验证
可以利用rest参数进行参数类型检查:
function checkTypes(...args) {
const types = args.map(arg => typeof arg);
console.log('参数类型:', types);
}
checkTypes(1, 'text', true, {}, []);
// 输出: ["number", "string", "boolean", "object", "object"]
实现函数组合
rest参数可以方便地实现函数组合:
function compose(...fns) {
return x => fns.reduceRight((v, f) => f(v), x);
}
const add5 = x => x + 5;
const multiply3 = x => x * 3;
const square = x => x * x;
const transform = compose(square, multiply3, add5);
console.log(transform(2)); // ((2 + 5) * 3)^2 = 441
创建可变参数的构造函数
在类中使用rest参数:
class Point {
constructor(...coords) {
this.coords = coords;
}
get dimensions() {
return this.coords.length;
}
}
const point2D = new Point(10, 20);
const point3D = new Point(10, 20, 30);
console.log(point2D.dimensions); // 2
console.log(point3D.dimensions); // 3
rest参数与扩展运算符的区别
虽然rest参数和扩展运算符都使用三个点(...)语法,但它们的作用相反:
- rest参数将多个参数收集到一个数组中
- 扩展运算符将数组或对象展开为多个元素
// rest参数:收集
function collect(...items) {
console.log(items);
}
// 扩展运算符:展开
const numbers = [1, 2, 3];
console.log(...numbers); // 等价于 console.log(1, 2, 3)
实际项目中的应用示例
实现一个简单的日志记录器
class Logger {
constructor(prefix = 'LOG') {
this.prefix = prefix;
}
log(...messages) {
const timestamp = new Date().toISOString();
console.log(`[${timestamp}] ${this.prefix}:`, ...messages);
}
}
const appLogger = new Logger('APP');
appLogger.log('用户登录', {username: 'admin'});
appLogger.log('数据加载完成', '耗时200ms');
创建灵活的API请求函数
async function apiRequest(method, endpoint, ...params) {
let options = {};
if (method === 'GET') {
endpoint += '?' + new URLSearchParams(params[0]).toString();
} else {
options = {
method,
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(params[0] || {})
};
}
const response = await fetch(endpoint, options);
return response.json();
}
// 使用示例
apiRequest('GET', '/api/users', {page: 1, limit: 10})
.then(data => console.log(data));
apiRequest('POST', '/api/users', {name: 'John', age: 30})
.then(data => console.log(data));
性能考虑
虽然rest参数提供了便利,但在性能敏感的场景需要注意:
- 每次函数调用都会创建一个新的数组实例
- 对于高频调用的函数,可能要考虑其他实现方式
- 在大多数应用场景中,这种性能开销可以忽略不计
// 性能测试示例
function testPerformance(fn, iterations = 1000000) {
const start = performance.now();
for (let i = 0; i < iterations; i++) {
fn(1, 2, 3, 4, 5);
}
return performance.now() - start;
}
function withRest(...args) {
return args.length;
}
function withoutRest(a, b, c, d, e) {
return arguments.length;
}
console.log('使用rest参数:', testPerformance(withRest), 'ms');
console.log('不使用rest参数:', testPerformance(withoutRest), 'ms');
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:函数调用中的展开使用