Home Web Front-end JS Tutorial Take control of loops with Symbol.iterator

Take control of loops with Symbol.iterator

Nov 08, 2024 am 07:16 AM

Take control of loops with Symbol.iterator

Have you ever used an Object.entries and wondered how it works? It is much simpler than you think!

Here's a basic implementation:

function objectEntries(obj) {
  const entries = [];

  for (const key in obj) {
    if (Object.hasOwn(obj, key)) {
      entries.push([key, obj[key]]);
    }
  }

  return entries;
}
Copy after login
Copy after login

However, this code is not quite good enough - what if the object was massive? The performance of the array based approach will have to be stored in memory for the whole process of executing this function. And if you use it again? It will have to build and keep a new array in memory just the same. In the real world, this can lead to serious performance issues and at some point we would need to accommodate for performance. However, there is an elegant solution which will solve all of these problems, in which Symbol.iterator comes to the rescue!

Here is an updated snippet:

function objectEntries(obj) {
  return {
    [Symbol.iterator]() {
      const keys = Object.keys(obj);
      let index = 0;

      return {
        next() {
          if (index < keys.length) {
            const key = keys[index++];
            return { value: [key, obj[key]], done: false };
          }
          return { done: true };
        }
      };
    }
  };
}
Copy after login
Copy after login

Why Use Symbol.iterator for Iteration?

In our initial implementation, the objectEntries function builds an array of all entries ([key, value] pairs) in memory, which can be a problem if the object has a large number of properties. Storing all the entries in an array means we have to allocate memory for every single pair in advance. This approach is fairly OK for smaller objects, but it quickly becomes inefficient and simply slow as object size grows.

In the updated code, we define [Symbol.iterator] on an object that holds the iteration logic. Let's break it down step-by-step:

  • Initialize Keys: Object.keys(obj) fetches an array of keys from the object obj. This list of keys allows us to know exactly what properties we need to access without storing every entry.
  • Use an Index Pointer: A variable index keeps track of our current position in the keys array. This is the only state we are going to have in the loop.
  • Define the next Method: The next() function uses index to retrieve the current key and increment it. It returns each [key, obj[key]] pair as a value, and sets done: true when we’ve iterated through all the keys.
  • By doing this, we enable objectEntries to be compatible with any for...of loop without the memory cost of creating an entire array of entries upfront.

Applying Symbol.iterator to custom loops

Let’s dive deeper into how these methods can provide more control over loop behavior. Each of the examples provided demonstrates a unique way to interact with array data, adding a lot of flexibility to your code. We'll explore the implications of each method and how they can be leveraged in different scenarios.

In these examples I am going to extend the Array prototype (more info on prototypes here) with the example methods to make my code easier to read. Let's jump right in!

For instance, this reverseIterator method can come in useful in something like a chat application where you might want to display the most recent messages first. Chat applications are notorious for having a LOT of data (messages in this case). Using reverseIterator, you can iterate through a list of messages and display them in the desired order without needing to create a new reversed array.

function objectEntries(obj) {
  const entries = [];

  for (const key in obj) {
    if (Object.hasOwn(obj, key)) {
      entries.push([key, obj[key]]);
    }
  }

  return entries;
}
Copy after login
Copy after login

This unique method enables you to iterate through an array while making sure that only unique values are yielded. This is super useful for eliminating duplicates on the fly, without filtering it in advance and using more memory.

function objectEntries(obj) {
  return {
    [Symbol.iterator]() {
      const keys = Object.keys(obj);
      let index = 0;

      return {
        next() {
          if (index < keys.length) {
            const key = keys[index++];
            return { value: [key, obj[key]], done: false };
          }
          return { done: true };
        }
      };
    }
  };
}
Copy after login
Copy after login

The chunk method below can be useful when dealing with large datasets, you can process them in smaller chunks to reduce memory usage and improve performance. Let's say you are importing data from something like a CSV file,you can read and process it in more scalable segments. Moreover, in web user interfaces, chunking can be used for pagination, allowing you to display a specific number of items per page or help you better manage an infinite loader.

Array.prototype.reverseIterator = function() {
  let index = this.length - 1;
  return {
    [Symbol.iterator]: () => ({
      next: () => {
        if (index >= 0) {
          return { value: this[index--], done: false };
        }
        return { done: true };
      }
    })
  };
};

const numbers = [1, 2, 3, 4, 5];
for (const num of numbers.reverseIterator()) {
  console.log(num); // 5, 4, 3, 2, 1
}
Copy after login

Conclusion

In this article, we explored how Symbol.iterator customizes the logic and improves the efficiency of our loops. By implementing custom iterable methods on the Array.prototype (or any other iterable to that effect), we can manage memory usage effectively and control how our loop is running.

The initial example of objectEntries demonstrated how an array-based approach can lead to performance issues when handling large objects. However, by using the SYmbol.iterator, we created an efficient solution that allows us to iterate over object entries without the overhead of unnecessary memory allocation.

We also looked at several practical examples of how extending the Array.prototype can facilitate various real-world scenarios developers have to deal with on a day-to-day basis.

With these powerful tools at your disposal, you're better equipped to solve complex data handling scenarios in JavaScript with close-to-zero performance implications on your app.

The above is the detailed content of Take control of loops with Symbol.iterator. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

What should I do if I encounter garbled code printing for front-end thermal paper receipts? What should I do if I encounter garbled code printing for front-end thermal paper receipts? Apr 04, 2025 pm 02:42 PM

Frequently Asked Questions and Solutions for Front-end Thermal Paper Ticket Printing In Front-end Development, Ticket Printing is a common requirement. However, many developers are implementing...

Demystifying JavaScript: What It Does and Why It Matters Demystifying JavaScript: What It Does and Why It Matters Apr 09, 2025 am 12:07 AM

JavaScript is the cornerstone of modern web development, and its main functions include event-driven programming, dynamic content generation and asynchronous programming. 1) Event-driven programming allows web pages to change dynamically according to user operations. 2) Dynamic content generation allows page content to be adjusted according to conditions. 3) Asynchronous programming ensures that the user interface is not blocked. JavaScript is widely used in web interaction, single-page application and server-side development, greatly improving the flexibility of user experience and cross-platform development.

Who gets paid more Python or JavaScript? Who gets paid more Python or JavaScript? Apr 04, 2025 am 12:09 AM

There is no absolute salary for Python and JavaScript developers, depending on skills and industry needs. 1. Python may be paid more in data science and machine learning. 2. JavaScript has great demand in front-end and full-stack development, and its salary is also considerable. 3. Influencing factors include experience, geographical location, company size and specific skills.

How to merge array elements with the same ID into one object using JavaScript? How to merge array elements with the same ID into one object using JavaScript? Apr 04, 2025 pm 05:09 PM

How to merge array elements with the same ID into one object in JavaScript? When processing data, we often encounter the need to have the same ID...

Is JavaScript hard to learn? Is JavaScript hard to learn? Apr 03, 2025 am 12:20 AM

Learning JavaScript is not difficult, but it is challenging. 1) Understand basic concepts such as variables, data types, functions, etc. 2) Master asynchronous programming and implement it through event loops. 3) Use DOM operations and Promise to handle asynchronous requests. 4) Avoid common mistakes and use debugging techniques. 5) Optimize performance and follow best practices.

How to achieve parallax scrolling and element animation effects, like Shiseido's official website?
or:
How can we achieve the animation effect accompanied by page scrolling like Shiseido's official website? How to achieve parallax scrolling and element animation effects, like Shiseido's official website? or: How can we achieve the animation effect accompanied by page scrolling like Shiseido's official website? Apr 04, 2025 pm 05:36 PM

Discussion on the realization of parallax scrolling and element animation effects in this article will explore how to achieve similar to Shiseido official website (https://www.shiseido.co.jp/sb/wonderland/)...

The Evolution of JavaScript: Current Trends and Future Prospects The Evolution of JavaScript: Current Trends and Future Prospects Apr 10, 2025 am 09:33 AM

The latest trends in JavaScript include the rise of TypeScript, the popularity of modern frameworks and libraries, and the application of WebAssembly. Future prospects cover more powerful type systems, the development of server-side JavaScript, the expansion of artificial intelligence and machine learning, and the potential of IoT and edge computing.

The difference in console.log output result: Why are the two calls different? The difference in console.log output result: Why are the two calls different? Apr 04, 2025 pm 05:12 PM

In-depth discussion of the root causes of the difference in console.log output. This article will analyze the differences in the output results of console.log function in a piece of code and explain the reasons behind it. �...

See all articles