Michael James
Michael's Coding Experience

Michael's Coding Experience

On Collections in JavaScript

Michael James's photo
Michael James
·May 12, 2022·

7 min read

Featured on Hashnode
On Collections in JavaScript

Table of contents

  • Introduction
  • The Plan
  • The Implementation
  • Conclusion

Introduction

While learning the JavaScript programming language, I didn't really create any code of much substance. I wrote code that manipulated strings, like titlecasing a string of any configuration. Then, I moved on to manipulating more complicating objects, and even nested objects of various complexity. Finally, towards the end of the journey of learning JavaScript, I worked through manipulating data from databases and nodejs-based backends. So, once I got through the learning phase, I wanted to work on something that actually did something more than any of those things I created before then.

I've been working on building out my portfolio for a few months now. The code is mostly implemented in JavaScript through the ReactJS framework frontend and there's usually something to the projects that requires some amount of backend implementation as well. I've mostly worked in nodejs, but I'm also interesting in using ReactJS with a Java backend, but I'll have to talk about that at a later time. For a while now, I've been working through the usual data structures while learning the intricacies of JavaScript.

I've been able to implement a few of the structures, so far. I meant to start with what seems to be the most essentially basic of the data structures, the Set. Once I set out the implement a Set in JavaScript, I decided that I wouldn't implement it by the usual basic primitive type that I've seen most coders use. I figured that it would be more of a challenge to use another type, so I decided to go with the most basic type in JavaScript, the object.

The Plan

I did have the realization that I would need to start with a more base structure than my implemented Set would entail. I figured this because a Set is a specific example of something more like a Collection, which seems to be more like an array in that:

  • there is a base index
  • each of which is to be incremented in some way, sequentially from that base index
  • there should be a property that defines the size of the collection, which is a non-negative integer

After doing some research on arrays and objects in JavaScript, I learned that the definition of the Collection that I intend to implement is called an array-like object. Then, I set out to implement each of the points listed above, as well as the ability to add and remove an element from the Collection, and get some specified element from the Collection or the entire Collection.

So, I have hit on each of the requirements of the Collection, except the second bullet-point that defines an array-like object. This point essentially defines an iterable object such that each of the elements of the object can be enumerated sequentially. I had yet implemented this type of object, so this aspect of the project piqued my interest. I'm always out to learn something new.

The Implementation

The Collection Object

I decided to implement the Collection as a functional expression:

const Collection = function() {
    let data = {};
    let length = 0;
};

with an object to contain the data of the Collection, and a variable to represent to the length initialized to zero, the base index.

Moving and Getting Data

Then, there need to be added to this object some functions to implement the requirements listed above:

  • add an element from the Collection
    this.push = function(element) {
         data[length] = element;
         length++;
         return data;
    };
    
    Here, we add the element at the key given by the current length of the object. Then, we increment the length of the object, so as to prepare the object to add a possible next element. Lastly, we return the object from the Collection.
  • remove an element from the Collection
    this.pop = function() {
          delete data[length-1];
          length--;
          return data;
    };
    
    Here, we remove the element at the key given by the previous length of the object. As the length of the object was incremented when the last element was added, the last element is actually off by one of the length recorded in the length property of the object. Then, we decrement the length of the object, so as to prepare the object to add a possible next element at the correct position. Lastly, we return the object from the Collection.

For this function, however, we have an issue that has not been resolved. This issue is intentional, as the Collection object is mean to be used to implement another object, where the issue will be resolved. The issue in question is the violation of the third point in the definition of an array-like object: The size of the object should be a non-negative integer. It is very possible to attempt to remove an element that doesn't exist. To avoid this issue, some sort of exception can be raised and caught accordingly.

  • get some specified element from the Collection
    this.get = function() {
         return data;
    };
    
    In this instance, we look to get the entire data object from the Collection. So, it is as simple as just returning the object.
  • get the entire Collection
    this.getElement = function(index) {
         return data[index];
    };
    
    In this instance, we look to get a specific value of the data object from the Collection. So, it is as simple as just returning the value at that index key in the object.

The Length of the Collection

Here, we look to obtain the length of the Collection, as part of the definition of an array-like object:

this.length = function() {
       return length;
};

So, just return the length calculated through the use of the object.

As mentioned in the previous section, it is possible to return a value that doesn't make sense according to the definition given above. After all, how is it possible to have a negative length? However, the Collection object is designed to be used as part of another data structure, so, as above, simply raising an exception in this case is sufficient to fix this issue.

Creating an Iterable Object

Per MDN docs, an iterable object is not a built-in object or something created from the JavaScript syntax. An iterable object is created using a protocol. This protocol allows the coder to specify the iteration behavior, such as what values are looped over using the for ... of construct. This object must implement the @@iterator method, meaning that the object must have a property with a @@iterator key which is available via constant Symbol.iterator. For our purposes with the Collection object, we have:

data[Symbol.iterator] = function() {
};

Whenever our Collection object needs to be iterated, the @@iterator method is called, and the returned iterator is used to get the values of the Collection that are to be iterated. So, from the function above, we return an object which contains the current index and a function, next(). This returned object should remind us of the returned object from a generator and it seems to operate as such, so it would pedagogically useful to think of it as such.

next() {
    if(this.index <= length) {
        let currentVal = this.index++;
        returnVal = {
            done: false,
            value: data[currentVal]
        };
     } else {
        returnVal = {
            done: true
        };
     }
     // return an iterator
     return returnVal;
}

Thus, on each iteration of the Collection, we end up with the generated values of the current value and a returned object defining whether the iteration is completed and the next value if the iteration has not completed.

Some Examples of Use

From my Github repository of the Collection object.

Instatiate the object.

const coll = new Collection();

Add or Remove some elements to or from the Collection.

coll.push(1);
coll.push(2);
coll.push(3);
coll.push(4);
coll.push(5);
coll.pop();
coll.pop();

The Collection contains the elements 1, 2, and 3. We can also get all the data from the Collection.

coll.get();

Or, we can get a particular element from the Collection. For instance, 3:

coll.getElement(2);

And we can also get the length of the Collection.

coll.length();

Conclusion

I set out to complete another task, but ended up writing this code. That process ended up teaching me a lot about the underlying structure in JavaScript. I'm not too sure that I would have written this code if I hadn't decided to create that original project in an unusual way to what I had seen before. I had such a great time with this project that I figured I should share the process with everybody else out there.

Going forward with this series, I'll go through in similar detail my process for creating this project. I do this to give myself a greater understanding of each project that I've worked on, as well as work on my communication skills and maybe help someone else out there with coding a project of his or her own. I figure that if I can explain these data structures, then I really do know what's going on.

 
Share this