如何在 JavaScript 中枚举/发现 getter 和 setter?

Eri*_*sen 10 javascript

我试图在打字稿中发现对象上的 getter 和 setter。我尝试过 Object.entries() 和 Object.keys() ,但这些都没有返回 getter 和 setter。我怎样才能列举这些呢?

编辑:这是一些显示问题的代码:

class ThingWithGetter{
  myProperty = 22;
  get myGetter() {return 1;}
}
const thing = new ThingWithGetter()

// Does not show getter
console.log(Object.keys(thing));

// Does not show getter
const descriptors = Object.getOwnPropertyDescriptors(thing);
console.log(Object.keys(descriptors));

// Does not show getter
console.log(Object.entries(thing))
Run Code Online (Sandbox Code Playgroud)

Asc*_*hen 6

您可以使用此函数枚举 getter 名称:

function listGetters (instance) {
  return Object.entries(
    Object.getOwnPropertyDescriptors(
      Reflect.getPrototypeOf(instance)
    )
  )
  .filter(e => typeof e[1].get === 'function' && e[0] !== '__proto__')
  .map(e => e[0]);
}
Run Code Online (Sandbox Code Playgroud)

它将返回一个包含 getter 名称的数组。


Stu*_*t K 5

这不起作用的原因是 getter 位于类的原型上,该原型位于实例的原型链上,而不是实例本身。

为了显示:

class A {
  get x() { return 1 }
}

aInstance = new A()
// A {}

Object.getOwnPropertyDescriptors(aInstance)
// {}

Object.getOwnPropertyDescriptors(A.prototype)
// { constructor:
//    { value: [Function: A],
//      writable: true,
//      enumerable: false,
//      configurable: true },
//   x:
//    { get: [Function: get x],
//      set: undefined,
//      enumerable: false,
//      configurable: true } }

Object.getOwnPropertyDescriptors(Object.getPrototypeOf(aInstance))
// { constructor:
//    { value: [Function: A],
//      writable: true,
//      enumerable: false,
//      configurable: true },
//   x:
//    { get: [Function: get x],
//      set: undefined,
//      enumerable: false,
//      configurable: true } }
Run Code Online (Sandbox Code Playgroud)

Axel Rauschmayer 关于这个主题有一些很好的博客文章:

请注意,如果您尝试枚举对象上的所有属性、访问器和方法,则需要递归地遍历原型链,直到对象具有原型null


kay*_*ya3 5

该函数Object.getOwnPropertyDescriptors位于 ECMAScript 最新草案规范中,但在流行的浏览器中实现。它返回属于对象的属性描述符。

您的用例有点困难,因为 getter 是在类上定义的,而不是对象本身。因此,您需要遍历原型链并以这种方式构建它。仅仅查看对象的原型是不够的,因为 getter 可以从对象类的任何超类继承。

这是一个执行此操作的递归函数:

function getAllPropertyDescriptors(obj) {
    if (!obj) {
        return Object.create(null);
    } else {
        const proto = Object.getPrototypeOf(obj);
        return {
            ...getAllPropertyDescriptors(proto),
            ...Object.getOwnPropertyDescriptors(obj)
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

的输出JSON.stringify(getAllPropertyDescriptors(thing))如下。myGetter是第三个属性描述符;如果您不使用 JSON.stringify ,则实际输出还包括对实际函数的引用,因此您可以查看它们是否具有get/set属性。

{
  "myProperty": {"value": 22, "writable": true, "enumerable": true, "configurable": true},
  "constructor": {"writable": true, "enumerable": false, "configurable": true},
  "myGetter": {"enumerable": false, "configurable": true},
  "__defineGetter__": {"writable": true, "enumerable": false, "configurable": true},
  "__defineSetter__": {"writable": true, "enumerable": false, "configurable": true},
  " hasOwnProperty ": {"writable": true, "enumerable": false, "configurable": true},
  "__lookupGetter__": {"writable": true, "enumerable": false, "configurable": true},
  "__lookupSetter__": {"writable": true, "enumerable": false, "configurable": true},
  "isPrototypeOf": {"writable": true, "enumerable": false, "configurable": true},
  "propertyIsEnumerable": {"writable": true, "enumerable": false, "configurable": true},
  "toString": {"writable": true, "enumerable": false, "configurable": true},
  "valueOf": {"writable": true, "enumerable": false, "configurable": true},
  "__proto__": {"enumerable": false, "configurable": true},
  "toLocaleString": {"writable": true, "enumerable": false, "configurable": true}
}
Run Code Online (Sandbox Code Playgroud)

您可以将其转换为迭代版本,但这可能是不必要的,因为大多数原型链都很短,并且迭代版本需要一些争论才能以正确的顺序进行覆盖。