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)

Hot Topics

Java Tutorial
1664
14
PHP Tutorial
1267
29
C# Tutorial
1239
24
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.

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.

JavaScript Engines: Comparing Implementations JavaScript Engines: Comparing Implementations Apr 13, 2025 am 12:05 AM

Different JavaScript engines have different effects when parsing and executing JavaScript code, because the implementation principles and optimization strategies of each engine differ. 1. Lexical analysis: convert source code into lexical unit. 2. Grammar analysis: Generate an abstract syntax tree. 3. Optimization and compilation: Generate machine code through the JIT compiler. 4. Execute: Run the machine code. V8 engine optimizes through instant compilation and hidden class, SpiderMonkey uses a type inference system, resulting in different performance performance on the same code.

Python vs. JavaScript: The Learning Curve and Ease of Use Python vs. JavaScript: The Learning Curve and Ease of Use Apr 16, 2025 am 12:12 AM

Python is more suitable for beginners, with a smooth learning curve and concise syntax; JavaScript is suitable for front-end development, with a steep learning curve and flexible syntax. 1. Python syntax is intuitive and suitable for data science and back-end development. 2. JavaScript is flexible and widely used in front-end and server-side programming.

JavaScript: Exploring the Versatility of a Web Language JavaScript: Exploring the Versatility of a Web Language Apr 11, 2025 am 12:01 AM

JavaScript is the core language of modern web development and is widely used for its diversity and flexibility. 1) Front-end development: build dynamic web pages and single-page applications through DOM operations and modern frameworks (such as React, Vue.js, Angular). 2) Server-side development: Node.js uses a non-blocking I/O model to handle high concurrency and real-time applications. 3) Mobile and desktop application development: cross-platform development is realized through ReactNative and Electron to improve development efficiency.

How to Build a Multi-Tenant SaaS Application with Next.js (Frontend Integration) How to Build a Multi-Tenant SaaS Application with Next.js (Frontend Integration) Apr 11, 2025 am 08:22 AM

This article demonstrates frontend integration with a backend secured by Permit, building a functional EdTech SaaS application using Next.js. The frontend fetches user permissions to control UI visibility and ensures API requests adhere to role-base

Building a Multi-Tenant SaaS Application with Next.js (Backend Integration) Building a Multi-Tenant SaaS Application with Next.js (Backend Integration) Apr 11, 2025 am 08:23 AM

I built a functional multi-tenant SaaS application (an EdTech app) with your everyday tech tool and you can do the same. First, what’s a multi-tenant SaaS application? Multi-tenant SaaS applications let you serve multiple customers from a sing

From C/C   to JavaScript: How It All Works From C/C to JavaScript: How It All Works Apr 14, 2025 am 12:05 AM

The shift from C/C to JavaScript requires adapting to dynamic typing, garbage collection and asynchronous programming. 1) C/C is a statically typed language that requires manual memory management, while JavaScript is dynamically typed and garbage collection is automatically processed. 2) C/C needs to be compiled into machine code, while JavaScript is an interpreted language. 3) JavaScript introduces concepts such as closures, prototype chains and Promise, which enhances flexibility and asynchronous programming capabilities.

See all articles