The rest parameter syntax
Basic Concepts of Rest Parameters
The rest parameter syntax introduced in ECMAScript 6 allows us to represent an indefinite number of arguments as an array. This syntax is implemented by adding three dots (...) before a function parameter, solving the cumbersome issue of using the arguments
object to handle variable arguments in ES5.
function sum(...numbers) {
return numbers.reduce((prev, curr) => prev + curr, 0);
}
console.log(sum(1, 2, 3)); // Outputs 6
console.log(sum(1, 2, 3, 4, 5)); // Outputs 15
Differences Between Rest Parameters and the arguments
Object
Rest parameters differ from the traditional arguments
object in several key ways:
- Rest parameters are true array instances and can directly use array methods.
- The
arguments
object contains all arguments, while rest parameters only include the remaining arguments that don't have corresponding formal parameters. - Rest parameters must be the last in the parameter list.
// Using the `arguments` object
function oldWay() {
const args = Array.prototype.slice.call(arguments);
return args.join('-');
}
// Using rest parameters
function newWay(...args) {
return args.join('-');
}
console.log(oldWay('a', 'b', 'c')); // "a-b-c"
console.log(newWay('a', 'b', 'c')); // "a-b-c"
Typical Use Cases for Rest Parameters
Collecting Function Arguments
The most common use of rest parameters is to collect excess function arguments:
function logWithPrefix(prefix, ...messages) {
messages.forEach(message => {
console.log(`${prefix}: ${message}`);
});
}
logWithPrefix('INFO', 'System started', 'Configuration loaded', 'Service ready');
Replacing the apply
Method
In ES5, we needed to use apply
to spread an array into arguments. Now, we can use rest parameters and the spread operator:
// ES5 way
Math.max.apply(null, [1, 2, 3]);
// ES6 way
Math.max(...[1, 2, 3]);
// Combining with rest parameters
function wrapper(...args) {
return Math.max(...args);
}
Rest Parameters in Destructuring Assignment
Rest parameter syntax can also be used in destructuring assignments:
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}
Notes on Rest Parameters
- Rest parameters must be the last parameter in a function:
// Incorrect example
function invalid(a, ...b, c) {
// SyntaxError: Rest parameter must be last formal parameter
}
- Rest parameters are not counted in a function's
length
property:
function func1(a, b) {}
function func2(a, b, ...c) {}
console.log(func1.length); // 2
console.log(func2.length); // 2
- Arrow functions can also use rest parameters:
const sum = (...nums) => nums.reduce((a, b) => a + b, 0);
Advanced Uses of Rest Parameters
Type Checking and Argument Validation
Rest parameters can be used for argument type checking:
function checkTypes(...args) {
const types = args.map(arg => typeof arg);
console.log('Argument types:', types);
}
checkTypes(1, 'text', true, {}, []);
// Output: ["number", "string", "boolean", "object", "object"]
Implementing Function Composition
Rest parameters make it easy to implement function composition:
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
Creating Variadic Constructors
Using rest parameters in classes:
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
Differences Between Rest Parameters and the Spread Operator
Although both rest parameters and the spread operator use the three-dot (...) syntax, they serve opposite purposes:
- Rest parameters collect multiple arguments into an array.
- The spread operator expands an array or object into multiple elements.
// Rest parameters: collecting
function collect(...items) {
console.log(items);
}
// Spread operator: expanding
const numbers = [1, 2, 3];
console.log(...numbers); // Equivalent to console.log(1, 2, 3)
Practical Application Examples
Implementing a Simple Logger
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('User logged in', {username: 'admin'});
appLogger.log('Data loaded', 'Time taken: 200ms');
Creating a Flexible API Request Function
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();
}
// Usage examples
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));
Performance Considerations
While rest parameters offer convenience, there are performance considerations in sensitive scenarios:
- Each function call creates a new array instance.
- For high-frequency function calls, alternative implementations may be necessary.
- In most application scenarios, this performance overhead is negligible.
// Performance test example
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('With rest parameters:', testPerformance(withRest), 'ms');
console.log('Without rest parameters:', testPerformance(withoutRest), 'ms');
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:函数调用中的展开使用