ES6迭代类方法

时间:2015-06-17 03:05:09

标签: javascript ecmascript-6

鉴于此课程;我将如何迭代它包含的方法?

class Animal {
    constructor(type){
        this.animalType = type;
    }
    getAnimalType(){
        console.log('this.animalType: ', this.animalType );
    }
}

let cat = window.cat = new Animal('cat')

我所尝试的是以下但没有成功:

for (var each in Object.getPrototypeOf(cat) ){
    console.log(each);
}

11 个答案:

答案 0 :(得分:54)

您可以在原型上使用Object.getOwnPropertyNames

Object.getOwnPropertyNames( Animal.prototype )
// [ 'constructor', 'getAnimalType' ]

答案 1 :(得分:11)

我知道,我知道,但是嘿......



const isGetter = ( x, name ) => ( Object.getOwnPropertyDescriptor( x, name ) || {} ).get
const isFunction = ( x, name ) => typeof x[ name ] === "function";
const deepFunctions = x => 
  x && x !== Object.prototype && 
  Object.getOwnPropertyNames( x )
    .filter( name => isGetter( x, name ) || isFunction( x, name ) )
    .concat( deepFunctions( Object.getPrototypeOf( x ) ) || [] );
const distinctDeepFunctions = x => Array.from( new Set( deepFunctions( x ) ) );
const userFunctions = x => distinctDeepFunctions( x ).filter( name => name !== "constructor" && !~name.indexOf( "__" ) );


// example usage

class YourObject {   
   hello() { return "uk"; }
   goodbye() { return "eu"; }
}

class MyObject extends YourObject {
   hello() { return "ie"; }
   get when() { return "soon"; } 
}

const obj = new MyObject();
console.log( userFunctions( obj ) ); // [ "hello", "when", "goodbye" ]




答案 2 :(得分:2)

由于ES6类上的方法是不可枚举的,因此您没有其他选择,只能使用Object.getOwnPropertyNames()来获取其所有属性的数组。

实现这一目标后,有几种方法可以提取方法,其中最简单的方法可能是使用Array.prototype.forEach()

查看以下代码段:

Object.getOwnPropertyNames(Animal.prototype).forEach((value) => {
    console.log(value);
})

答案 3 :(得分:1)

这有点复杂,但是可以从整个原型链中获取方法。

function getAllMethodNames (obj, depth = Infinity) {
    const methods = new Set()
    while (depth-- && obj) {
        for (const key of Reflect.ownKeys(obj)) {
            methods.add(key)
        }
        obj = Reflect.getPrototypeOf(obj)
    }
    return [...methods]
}

答案 4 :(得分:0)

检查这个小提琴

https://jsfiddle.net/ponmudi/tqmya6ok/1/

class Animal {
    constructor(type){
        this.animalType = type;
    }
    getAnimalType(){
        console.log('this.animalType: ', this.animalType );
    }
}

let cat = new Animal('cat');

//by instance
document.getElementById('1').innerHTML = Object.getOwnPropertyNames(cat);

//by getting prototype from instance
document.getElementById('2').innerHTML = Object.getOwnPropertyNames(Object.getPrototypeOf(cat));

//by prototype
document.getElementById('3').innerHTML = Object.getOwnPropertyNames(Animal.prototype);

答案 5 :(得分:0)

如果您还需要获取超类方法,可以反复调用Object.getPrototypeOf(),直到找到所有方法。当你到达Object.prototype时,你可能想要停下来,因为那里的方法很基础,你通常不想用任何使用反射的代码触摸它们。

问题Get functions (methods) of a class有一个答案,其中包含一个执行此操作的函数,但它有一些缺点(包括使用一个循环条件,它具有修改函数参数的副作用,我认为这有两个问题代码样式选择在一行代码中...),所以我在这里重写了它:

export function listMethodNames (object, downToClass = Object)
{
    // based on code by Muhammad Umer, https://stackoverflow.com/a/31055217/441899
    let props = [];

    for (let obj = object; obj !== null && obj !== downToClass.prototype; obj = Object.getPrototypeOf(obj))
    {
        props = props.concat(Object.getOwnPropertyNames(obj));
    }

    return props.sort().filter((e, i, arr) => e != arr[i+1] && typeof object[e] == 'function');
}

除了修复原始代码中的错误(它没有将对象复制到循环的另一个变量中,所以当它用于在返回行中进行过滤时,它不再有效)给出一个可选参数来停止可配置类的迭代。它默认为Object(因此排除Object的方法;如果要包含它们,则可以使用不会出现在继承链中的类......也许制作一个标记类,例如class IncludeObjectMethods{}可能有意义。我还将do循环更改为更清晰的for循环,并将旧式function ...过滤器函数重写为ES6箭头函数,以使代码更紧凑。

答案 6 :(得分:0)

对于使用对此类问题感兴趣的Typescript的任何人,您可以使用元数据反射API以简单的方式执行许多操作。例如,您可以使用装饰器向类添加元数据,并获取有关类方法,属性及其类型的信息。 Typescript及其类型允许对编译语言(如java,c#和它们的内省apis)执行类似的操作。

请查看这些链接以获取更多信息:

https://www.typescriptlang.org/docs/handbook/decorators.html

https://www.npmjs.com/search?q=reflect-metadata

答案 7 :(得分:0)

如果仅需要功能(例如替换为_.functions),请尝试这种单线方式

function getInstanceMethodNames (obj) {
    return Object
        .getOwnPropertyNames (Object.getPrototypeOf (obj))
        .filter(name => (name !== 'constructor' && typeof obj[name] === 'function'));
}

答案 8 :(得分:0)

这是此处https://stackoverflow.com/a/35033472/3811640

建议的答案的增强版本。

默认情况下,我添加参数deep,deep = Infinity来提取所有函数,包括父函数。 deep = 1提取给定类的直接方法。

getAllMethods = function (obj, deep = Infinity) {
    let props = []

    while (
      (obj = Object.getPrototypeOf(obj)) && // walk-up the prototype chain
      Object.getPrototypeOf(obj) && // not the the Object prototype methods (hasOwnProperty, etc...)
      deep !== 0
    ) {
      const l = Object.getOwnPropertyNames(obj)
        .concat(Object.getOwnPropertySymbols(obj).map(s => s.toString()))
        .sort()
        .filter(
          (p, i, arr) =>
            typeof obj[p] === 'function' && // only the methods
            p !== 'constructor' && // not the constructor
            (i == 0 || p !== arr[i - 1]) && // not overriding in this prototype
            props.indexOf(p) === -1 // not overridden in a child
        )
      props = props.concat(l)
      deep--
    }

    return props
  }
  

class Foo {
  
  method01 (){
  }
  
  method02 (){
  }
  
  }
  
  
  class FooChield extends Foo {
  
  method01(){
  }
  
  method03(){
  }
  } 
  

  
  console.log('All methods', getAllMethods(new FooChield())) 
  
  console.log('Direct methods', getAllMethods(new FooChield(),1))

enter code here

答案 9 :(得分:0)

另一种无需列出构造函数和其他属性即可获取它们的方法:

var getMethods = function(obj) {
    const o = Reflect.getPrototypeOf(obj);
    const x = Reflect.getPrototypeOf(o);
    return Reflect.ownKeys(o).filter(it => Reflect.ownKeys(x).indexOf(it) < 0);
}

答案 10 :(得分:0)

为什么这里的答案如此复杂?让我们简单点。

Object.getOwnPropertyNames(...) 是获取非继承类方法名称的标准且唯一的方法。 [按字母顺序作为数组返回]

Object.getPrototypeOf(...) 是获取继承原型的标准且唯一的方法。 [作为 Class.prototype 返回]

所以,只是循环

  Object.getPrototypeOf(Object.getPrototypeOf( 
    Object.getPrototypeOf( Object.getPrototypeOf(  
      ...
        Object.getPrototypeOf( your_object )
      ...
    ))
  ))

直到它的构造函数 === Object

  // JavaScript

  class A {
     myWife() {   console.log(4)   }
  }
  class B extends A {
     myParent() {   console.log(5)   }
  }
  class C extends B {
     myBrother() {   console.log(6)   }
  }
  class D extends C {
     mySelf() {   console.log(7)   }
  }
  
  let obj = new D;
  
  function classMethodsA(obj) {
    let res = {};
    let p = Object.getPrototypeOf(obj)
    while (p.constructor !== Object) {
      for(const k of Object.getOwnPropertyNames(p)){
        if (!(k in res)) res[k] = obj[k];
      }
      p = Object.getPrototypeOf(p)
    }
    return res;
  }
  
    
  function classMethodsB(obj) {
    let res = [];
    let p = Object.getPrototypeOf(obj);
    while (p.constructor !== Object) {
      for(const k of Object.getOwnPropertyNames(p)){
        if (!res.includes(k)) res.push(k);
      }
      p = Object.getPrototypeOf(p);
    }
    return res;
  }
  
  
  document.body.innerHTML=`
<p>  -- No Constructor -- ${Object.keys(classMethodsA(obj))}</p>
<p>  -- With Constructor -- ${classMethodsB(obj)}</p>
  `;