How can support Object.entries being called on an instance of my class - javascript / nodejs?

Solution 1:

The issue is that your instances have no public "own" (not inherited) properties, which is what Object.entries includes in its array.

I am trying to get my class to behave like a "normal" object, in that when it is called in object.entries it returns an array of key value pairs.

That's the default behavior, whether you create the object via a class constructor or some other way.

After quite a bit of searching around I have been able to make my class iterable.

Object.entries has nothing to do with whether an object is iterable.

I don't think you can make Object.entries return [[name, "value"]] without making name an "own" data property. But you can make it a read-only own data property via Object.defineProperty:

class Person {
    #name;

    constructor(name) {
        this.#name = name;
        Object.defineProperty(this, "name", {
            value: name,
            writable: false,
            enumerable: true,
            configurable: true
        });
    }
}

const bill = new Person("Bill");
console.log(`bill.name:`, bill.name);
console.log(`Object.entries(bill):`, Object.entries(bill));

I've kept #name there, but there's probably no reason for it, so:

class Person {
    constructor(name) {
        Object.defineProperty(this, "name", {
            value: name,
            writable: false,
            enumerable: true,
            configurable: true
        });
    }
}

const bill = new Person("Bill");
console.log(`bill.name:`, bill.name);
console.log(`Object.entries(bill):`, Object.entries(bill));

If you want to be able to set name internally, just give yourself a private method that repeates the defineProperty:

class Person {
    constructor(name) {
        this.#setName(name);
    }
    
    #setName(name) {
        Object.defineProperty(this, "name", {
            value: name,
            writable: false,
            enumerable: true,
            configurable: true
        });
    }
}

const bill = new Person("Bill");
console.log(`bill.name:`, bill.name);
console.log(`Object.entries(bill):`, Object.entries(bill));

Unfortunately, because the property is configurable, your code isn't the only code that can use defineProperty to change it. (This is rather like the name property on functions, which is read-only by default but can be changed via defineProperty.) So it's not exactly the same as having #name and get name, it's just close while providing support for Object.entries.