阿里云主机折上折
  • 微信号
Current Site:Index > Rest/Spread properties

Rest/Spread properties

Author:Chuan Chen 阅读数:24954人阅读 分类: JavaScript

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:

  1. The Rest element must be the last element in the destructuring pattern.
  2. It only collects the object's own enumerable properties.
  3. 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:

  1. Properties from later objects override those of earlier objects with the same name.
  2. Only the object's own enumerable properties are expanded.
  3. 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

  1. 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
    
  2. Non-enumerable Properties: Spread only copies enumerable properties.

    const obj = Object.defineProperty({}, 'hidden', {
      value: 'secret',
      enumerable: false
    });
    
    console.log({ ...obj }); // {}
    
  3. Performance Considerations: Frequent use of Spread with large objects may cause performance issues.

  4. 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

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.