使用原型时,得到类的方法

问题描述 投票:0回答:3

我写一些代码来扩展Object,我想遍历对象中的方法。当我输出this.constructor的值,我看到我想(在下面的例子中我看到test)的方法。然而,当我环并且使用为这些方法,它只显示方法getType。我怎样才能得到class A的只是方法?

Object.prototype.getType = function () {
  // Outputs correct class and methods
  console.log(this.constructor)

  for (let i in this.constructor) {
    // Outputs wrong methods
    console.log(i)
  }
}

class A {
  test() {console.log('hello')}
}

new A().getType()
javascript
3个回答
2
投票

两个问题:

  1. 属性可以枚举 - 或不 - 由...在循环中访问。当您在class定义一个方法,默认是不可枚举。 (Object.prototype.getType,在另一方面,是枚举,因为这是默认的,当您通过分配的属性。)
  2. 你遍历的对象所宣称的属性是它的构造,但像test非静态的方法是构造函数的prototype财产(A.prototype)的性质,而不是构造函数本身(A.test不是一回事)。

你可以找到与Object.getOwnPropertyNames功能不可枚举的属性:

Object.prototype.getType = function () {
  for (let name of Object.getOwnPropertyNames(this.constructor.prototype)) {
    console.log(name)
  }
}

请注意,这不仅包括自己的属性 - 性能直接在物体上 - 所以,如果你想包括继承的方法,你就必须去检查原型链。

function* getAllPropertyNames(obj) {
  do {
    yield* Object.getOwnPropertyNames(obj)
  } while (obj = Object.getPrototypeOf(obj))
}

Object.prototype.getType = function () {
  for (let name of getAllPropertyNames(this.constructor.prototype)) {
    console.log(name)
  }
}

如果你要包括直接在物体上的属性,你就必须从这里开始(希望this.constructor.prototypeObject.getPrototypeOf(this))。

Object.prototype.getType = function () {
  for (let name of getAllPropertyNames(this)) {
    console.log(name)
  }
}

另外,不要延长Object.prototype。特别是没有枚举的属性。管理不负责,当你做到这一点,在神秘的方式打破依赖。


1
投票

也许不是最完美的解决方案,但要做到这一点的一种方式是通过调用Object.getOwnPropertyNames(),传递对象实例__proto__参考。

Object.prototype.getType = function () {

  /*
  // Outputs correct class and methods
  console.log(this.constructor)

  for (let i in this.constructor) {
    // Outputs wrong methods
    console.log(i)
  }
  */

  for(let j of Object.getOwnPropertyNames(this.__proto__)
  .filter(method => method !== 'constructor')) 
  {
    // Outputs properties of prototype, without constructor method
    console.log(j);
  }
  
}

class A {
  test() {console.log('hello')}
}

new A().getType()

1
投票

对GetType名字似乎不合适,你要找的是什么性质,所以getAllProperties似乎一个更好的名字。

正如其他人所说,你需要去了[[Prototype]]链有许多原因:

  1. 从对象其构造函数的原型,而不是构造函数本身继承
  2. constructor属性可能不会指向实际构造
  3. 该constructor.prototype可能不是用于创建该对象的一个
  4. 可能有多个构造
  5. 继承属性可以被复制,你需要得到的只是“最近的”一个

所述[[Prototype]]链在零结束,这是原型的Object.prototype是所有原型的层次结构的顶部。该函数也应删除重复,可在每个原型发生(例如构造,并且长度是很常见)。

function getAllProperties(obj) {
  // Recursively get properties up [[Prototype]] chain
  function loop(obj) {
    let props = Object.getOwnPropertyNames(obj);
    let proto = Object.getPrototypeOf(obj);
    
    // Stop at null
    if (proto !== null) {
      return props.concat(loop(proto));
    }
    return props;
  }
  
  let allProps = loop(obj);
  
  // Remove duplicates
  return allProps.filter((prop, i) => !allProps.includes(prop, i+1));
}

console.log(getAllProperties('a'))

如果你只想方法,然后过滤,你去typeof x == 'function'

function getAllMethods(obj) {
  // Recursively get properties up [[Prototype]] chain
  function loop(obj) {
    // Get all properties, filter for functions
    let props = Object.getOwnPropertyNames(obj).filter((prop, i, props) => typeof props[prop] == 'function');
    let proto = Object.getPrototypeOf(obj);

    // Stop at null
    if (proto !== null) {
      return props.concat(loop(proto));
    }
    return props;
  }

  let allMethods = loop(obj);

  // Remove duplicates
  return allMethods.filter((prop, i) => !allMethods.includes(prop, i + 1));
}

console.log(getAllMethods('a'))
© www.soinside.com 2019 - 2024. All rights reserved.