Rest/Spread properties
ECMAScript 9 (ES2018) introduced enhanced Rest/Spread properties, further simplifying operations on objects and arrays. These features allow developers to handle data structures more flexibly, particularly excelling in scenarios like function parameter passing and object merging.
Application of Rest Parameters in Object Destructuring
Rest parameters (...
) in object destructuring allow collecting the remaining enumerable properties. This feature is particularly useful when dealing with objects with an uncertain number of properties:
const person = {
name: 'Alice',
age: 25,
job: 'Engineer',
country: 'USA'
};
const { name, age, ...rest } = person;
console.log(name); // 'Alice'
console.log(rest); // { job: 'Engineer', country: 'USA' }
Key points to note:
- The Rest element must be the last element in the destructuring pattern.
- It only collects the object's own enumerable properties.
- It does not include properties inherited from the prototype chain.
A more complex example demonstrates nested destructuring:
const config = {
api: {
endpoint: 'https://api.example.com',
timeout: 5000,
retries: 3
},
logging: {
level: 'debug',
format: 'json'
}
};
const {
api: { endpoint, ...apiRest },
...configRest
} = config;
console.log(endpoint); // 'https://api.example.com'
console.log(apiRest); // { timeout: 5000, retries: 3 }
console.log(configRest); // { logging: { level: 'debug', format: 'json' } }
Usage of Spread Properties in Object Literals
Spread properties (...
) allow expanding the enumerable properties of one object into another. This provides a concise way to achieve shallow copying and merging of objects:
const defaults = {
theme: 'light',
fontSize: 14,
notifications: true
};
const userSettings = {
theme: 'dark',
showHelp: false
};
const merged = {
...defaults,
...userSettings
};
console.log(merged);
// {
// theme: 'dark',
// fontSize: 14,
// notifications: true,
// showHelp: false
// }
Behavioral characteristics of Spread properties:
- Properties from later objects override those of earlier objects with the same name.
- Only the object's own enumerable properties are expanded.
- The order of expansion affects the final result.
In practical applications, it can be used for immutable updates:
const state = {
user: {
name: 'Bob',
preferences: {
theme: 'dark',
notifications: true
}
},
loading: false
};
const updatedState = {
...state,
user: {
...state.user,
preferences: {
...state.user.preferences,
theme: 'light'
}
}
};
Rest/Spread Operations in Arrays
Although Rest/Spread for arrays was introduced in ES6, it was handled more consistently in ES9:
// Rest in array destructuring
const numbers = [1, 2, 3, 4, 5];
const [first, second, ...others] = numbers;
console.log(others); // [3, 4, 5]
// Spread in array literals
const newNumbers = [0, ...numbers, 6];
console.log(newNumbers); // [0, 1, 2, 3, 4, 5, 6]
A practical example of function parameter handling:
function processData(data, ...callbacks) {
const result = data.map(item => item * 2);
callbacks.forEach(cb => cb(result));
}
processData(
[1, 2, 3],
res => console.log('Result:', res),
res => console.log('Length:', res.length)
);
Practical Application Scenarios
Function Parameter Handling
Rest parameters enable functions to accept any number of arguments:
function logItems(preface, ...items) {
console.log(preface);
items.forEach((item, i) => console.log(` ${i + 1}. ${item}`));
}
logItems('Shopping list:', 'Apples', 'Bread', 'Milk');
Object Merging and Overriding
Spread properties simplify configuration merging:
function createConfig(baseConfig, overrideConfig) {
return {
...baseConfig,
...overrideConfig,
// Deep properties require separate handling
nested: {
...baseConfig.nested,
...overrideConfig.nested
}
};
}
Passing Props in React Components
Spread is widely used in React for passing props:
function Button({ variant, children, ...props }) {
return (
<button
className={`btn ${variant}`}
{...props}
>
{children}
</button>
);
}
// Usage
<Button variant="primary" onClick={handleClick} disabled>
Submit
</Button>
Considerations and Edge Cases
-
Prototype Chain Properties: Spread does not copy properties from the prototype chain.
class Person { constructor(name) { this.name = name; } greet() { console.log(`Hello, ${this.name}`); } } const alice = new Person('Alice'); const clone = { ...alice }; console.log('greet' in clone); // false
-
Non-enumerable Properties: Spread only copies enumerable properties.
const obj = Object.defineProperty({}, 'hidden', { value: 'secret', enumerable: false }); console.log({ ...obj }); // {}
-
Performance Considerations: Frequent use of Spread with large objects may cause performance issues.
-
Differences from Object.assign:
const obj = { a: 1 }; const withSpread = { ...obj, a: 2 }; // { a: 2 } const withAssign = Object.assign({}, obj, { a: 2 }); // { a: 2 } // The main difference is that Spread triggers getters, while Object.assign does not.
Combining with Other ES9 Features
Rest/Spread properties can be combined with other ES9 features like asynchronous iteration and Promise.finally:
async function fetchAll(...urls) {
const responses = await Promise.all(
urls.map(url => fetch(url).then(res => res.json()))
);
return responses.flat();
}
Application in regex named capture groups:
function extractDate(text) {
const { groups } = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/.exec(text);
return { ...groups };
}
Rest/Spread in TypeScript
TypeScript provides full type support for Rest/Spread properties:
interface Person {
name: string;
age: number;
location?: string;
}
function updatePerson(person: Person, updates: Partial<Person>) {
return { ...person, ...updates };
}
const person: Person = { name: 'Alice', age: 30 };
const updated = updatePerson(person, { age: 31 });
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:模块的异步加载
下一篇:正则表达式命名捕获组