ES6迭代类方法

58

给定这个类,我该如何迭代其中包含的方法?

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

1
遍历Animal.prototype不应该有效吗?据我所知,基础对象架构仍然与“旧”方式相同。 - slebetman
Animal.prototype公开了这些方法。我认为问题在于迭代它们的方式。for..in似乎不起作用。 - seasick
12个回答

80
您可以在原型上使用Object.getOwnPropertyNames
Object.getOwnPropertyNames( Animal.prototype )
// [ 'constructor', 'getAnimalType' ]

我还没有尝试过这个 - 但是这个会在继承了某些东西的情况下工作吗?我不确定它是否只适用于超类。 - seasick
12
它有效,但你需要先使用 Object.getPrototypeOf 来获取原型:Object.getOwnPropertyNames(Object.getPrototypeOf(cat)) - Paul
谢谢!!!那肯定可以用,但考虑到所有语法...我想知道这是否是做这样事情的首选方式。我想要的是只调用类的所有方法,但不想以字面类型的方式执行,所以我想要迭代它们。 - seasick
4
е“ҰпјҢеҰӮжһңдҪ жғіиҺ·еҸ–Animal继жүҝиҮӘе…¶д»–еҹәзұ»зҡ„ж–№жі•пјҢеҲҷиҝҳйңҖиҰҒйҖ’еҪ’ең°йҒҚеҺҶеҺҹеһӢй“ҫд»ҘиҺ·еҸ–й“ҫдёӯжҜҸдёӘеҜ№иұЎзҡ„getOwnPropertyNamesгҖӮжҲ‘и®ӨдёәжІЎжңүе…¶д»–ж–№жі•еҸҜд»Ҙи®ҝй—®дёҚеҸҜжһҡдёҫеұһжҖ§гҖӮ - Paul
请注意,getOwnPropertyNames 不会返回继承的方法,如果你的类继承了另一个类,那些方法将不会被包括在内。 - Adam Reis
请注意,getOwnPropertyNames 返回的是已排序的列表,而不是反映声明顺序的列表。 - Mike 'Pomax' Kamermans

24

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

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" ]


应该选择这个答案,它适用于ES6和动态对象以及ES6继承。 - ktutnik
4
x [ name ] 将会执行一个 getter 函数。使用 (Object.getOwnPropertyDescriptor(x, name) || {}).get || typeof x [ name ] == ... 进行防护。 - Samuel Danielson
1
@goofballLogic,您应该检查属性是否仍然存在。可以使用“delete”命令删除属性。 - Yairopro

7

如果你只需要函数(例如替换为 _.functions),可以尝试这种线性方式。

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

7
这有点更详细,但可以从整个原型链中获取方法。
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]
}

6

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

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

请查看以下代码片段:

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

2

这是对此处建议的回答的增强版本https://dev59.com/Gl0Z5IYBdhLWcg3wzC5W#35033472

我添加了参数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))


2

检查这个 fiddle

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

1
我会在这里添加我的版本,以供其他可能需要的人使用。此版本获取所有类型为函数的属性和成员,同时排除存在于Object.prototype上的任何内容,并返回具有相同键和与其对应的函数的对象。
示例
class Alpha {
  a = 'a'
  b = () => 'b'
  c = function() { return 'c' }
  d() {
    return 'd'
  }
}

class Beta {
  e = 'e'
  f = () => 'f'
  g = function() { return 'g' }
  h() {
    return 'h'
  }
}

const functions = getAllFunction(new Beta())

// functions
// {
//   b: () => 'b',
//   c: function() { return 'c'},
//   d: function() { return 'd' },
//   f: () => 'f',
//   g: function() { return 'g' },
//   h: function() { return 'h' }
// }

function getAllFunctions(source) {
  const functions = {}
  const objectPrototypeKeys = Reflect.ownKeys(Object.prototype)
  let prototype = Reflect.getPrototypeOf(source)

  // properties
  Reflect.ownKeys(source).forEach(key => {
    if (typeof key === 'string' && typeof source[key] === 'function') {
      functions[key] = source[key]
    }
  })

  // methods
  while (prototype && prototype !== Object.prototype) {
    Reflect.ownKeys(prototype).forEach(key => {
      if (typeof key === 'string' && typeof context[key] === 'function' && !objectPrototypeKeys.includes(key)) {
        functions[key] = (prototype as any)[key]
      }
    })

    prototype = Reflect.getPrototypeOf(prototype)
  }

  return functions
}

1

获取它们的另一种方式是不列出构造函数和其他属性:

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

0

一种获取继承方法但不包括Object方法和可选getter的方法:

const getMethods = (obj, getters) => {
  const orig = obj
  let keys = []
  do {
    keys = keys.concat(Object.getOwnPropertyNames(obj))
    if (!getters)
      keys = keys.filter(k => !(Object.getOwnPropertyDescriptor(obj, k) || {}).get)
    obj = Object.getPrototypeOf(obj)
  } while (obj && obj.constructor && obj.constructor.name !== 'Object')
  return Array.from(new Set(keys))
    .filter(k => k !== 'constructor' && typeof orig[k] === 'function')
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接