如何支持在我的 class - javascript / nodejs 的实例上调用 Object.entries?

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

我试图让我的 class 表现得像一个“普通”对象,因为当它在 object.entries 中被调用时,它 returns 是一个键值对数组。经过大量搜索后,我已经能够使我的 class 可迭代。但是我找不到从哪里开始实施 object.entries.

这里是我的目的地,

'use strict'

class Person {
    #name

    constructor(name) {
        this.#name = name
    }

    get name () {
        return this.#name
    }

    *iterator () {

        var props = Object.getOwnPropertyNames(Object.getPrototypeOf(this))
        for (const prop of props) {

            if (typeof this[prop] !== 'function') {
                const o = {}
                o[prop] = this[prop]

                yield o
            }
        }
    }

    [Symbol.iterator] () {
        return this.iterator()
    }
}

const person = new Person ('bill')

//works - produces { name: 'bill' }
for (const prop of person){
    console.log (prop)
}

// doesn't work.  Prints an empty array
console.log (Object.entries(person))

实际上您不必实现迭代器。 Object.entries 不起作用的原因是由于 # 属性 被视为私有的,因此不会返回。如果您删除 # name 将由 Object.entries 返回,如下例所示。

class Person {
    name

    constructor(name) {
        this.name = name
    }
}

const person = new Person ('bill')


// doesn't work.  Prints an empty array
console.log(Object.entries(person))

问题是您的实例没有 public“自己的”(不是继承的)属性,Object.entries 包含在其数组中。

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.

这是默认行为,无论您是通过 class 构造函数还是其他方式创建对象。

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

Object.entries与对象是否可迭代无关。

我认为如果不将 name 设为“自己的”数据 属性,就无法制作 Object.entries return [[name, "value"]]。但是您可以通过 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));

我一直 #name 在那里,但可能没有理由这样做,所以:

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));

如果你希望能够在内部设置 name,只需给自己一个重复 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));

不幸的是,因为 属性 是可配置的,所以您的代码不是唯一可以使用 defineProperty 来更改它的代码。 (这很像函数上的 name 属性,默认情况下它是只读的,但可以通过 defineProperty 更改。)所以它与 [=19= 不完全相同] 和 get name,它只是在为 Object.entries.

提供支持时关闭