0

I'm learning to make objects iterable in Javascript.

My object is:

var arrayLikeObject = {
    0: "hello",
    1: "there",
    2: "crappy coder",
    length: 3,
}

then I do this to make it iterable:

arrayLikeObject[Symbol.iterator] = function(){
    return {
        current: 0, // <---- but... it IS defined.
        next() {
            // let current = 0; // putting it here makes it work
            if(current < this.length) {
                let a = current;
                current++;
                return {done: false, value: this[a]};
            }
            else {
                return {done: true};
            }
        }
    };
};

then when I run it with:

console.log("after making it iterable: ==============");
for(let str of arrayLikeObject) {
    console.log(str);
}

I get "current is not defined". But as far as I can see, it is defined. I don't understand. I thought functions could see variables outside their scope, but not the other way around, unless they get "overshadowed".

3
  • 6
    current -> this.current. A variable and an object property are different in JS. Commented Oct 20, 2020 at 12:05
  • Gotcha. Kinda forgot one needs to use this in object methods when creating an object literal, to use objects properties in its methods :-o. Is there another venue for questions like this, where someone just needs help when getting mentally blocked (after googling, checking tutorials and stackoverflow answer, and still cant get "unstuck"). Like, a second pair of eyes? Guessing these kind of questions get downvoted prety quickly x) Commented Oct 20, 2020 at 12:17
  • Actually. Just noticed (because of a bunch of other printouts getting in the way. It still does not work, I get no error by using if(this.current < this.length) anymore, but I get no results from the for...of loop either. Commented Oct 20, 2020 at 12:22

1 Answer 1

4

current is not a variable, it is a property, so you would need to reference it as this.current.

However, you have another issue with this:

In this.length and this[a], the this object is not arrayLikeObject, but the object that has the next() method.

You can also fix this, but I think it is simpler to go the other way, and make next an arrow function. That way this.length and this[a] will work as intended. Make current a normal variable within the closure:

const arrayLikeObject = {
    0: "hello",
    1: "there",
    2: "crappy coder",
    length: 3,
}

arrayLikeObject[Symbol.iterator] = function(){
    let current = 0;
    return {
        next: () => {
            if(current < this.length) {
                return {done: false, value: this[current++]};
            }
            else {
                return {done: true};
            }
        }
    };
};

console.log(...arrayLikeObject);

Note that you don't really have to create a new function, as you can just assign Array.prototype[Symbol.iterator]:

const arrayLikeObject = {
    0: "hello",
    1: "there",
    2: "crappy coder",
    length: 3,
}

arrayLikeObject[Symbol.iterator] = Array.prototype[Symbol.iterator];

console.log(...arrayLikeObject);

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. Rewrote it by explicitly creating an object and then after populating it before returning it (object called iterator). Avoided arrow functions, hence had to keep track of "this" and share it explicitly. Didn't want to present yet another thing, arrow functions, that i'm not comfortable with. Your explanation totally helped though :). I accept your answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.