【问题标题】:How can support Object.entries being called on an instance of my class - javascript / nodejs?如何支持在我的类的实例上调用 Object.entries - javascript / nodejs?
【发布时间】:2022-01-11 07:39:46
【问题描述】:

我试图让我的类表现得像一个“正常”对象,因为当它在object.entries 中调用时,它返回一个键值对数组。经过相当多的搜索,我已经能够使我的类可迭代。但我无法找到实施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))

【问题讨论】:

    标签: javascript node.js oop


    【解决方案1】:

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

    我试图让我的类表现得像一个“普通”对象,因为当它在 object.entries 中被调用时,它会返回一个键值对数组。

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

    经过相当多的搜索,我已经能够使我的类可迭代。

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

    我认为你不能让Object.entries 返回[[name, "value"]] 而不使name 成为“自己的”数据属性。但是您可以通过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 进行更改。)所以它与#nameget name 并不完全相同,它只是关闭而为Object.entries提供支持。

    【讨论】:

    • 感谢您解释 Object.entries 和公共属性。我的想法是,因为我公开了创建这些公共属性的 getter,但我想这不是 javascript 看到它的方式 Re 需要 #name,我在我的代码中错过了它,但它在那里支持设置名称.所以我的班级应该有 set name (value) { this.#name = value } ....(除非有更好的方法来跟踪状态...)感谢代码 sn-ps 并将标记作为回答
    【解决方案2】:

    您实际上不必实现迭代器。 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))

    【讨论】:

    • #name 可能是私有的,并且仅通过设置器出于某种原因公开。这段代码也没有多大意义,它在实例上创建了一个名为 name 的数据属性,还在原型上创建了一个 name 访问器。
    • 谢谢我错过了吸气剂。如果属性应该保留private,则问题的名称应该更具体,因为它与how to return a private property with a getter when using Object,entries
    猜你喜欢
    • 2016-05-07
    • 2014-11-21
    • 2016-05-18
    • 2012-06-04
    • 1970-01-01
    • 2011-09-13
    • 1970-01-01
    • 2023-03-13
    • 1970-01-01
    相关资源
    最近更新 更多