Q: 如何遍历class中的原型方法?

3,581 阅读2分钟

es6中的class算是构造函数的语法糖,但它和构造函数在特征和用法上还是有些不同的。

如果是用function构造函数写法的话,我们可以用Object.keys或者for...in来遍历它的原型

function Test() {}
Test.prototype.testMethod = function(){}
const fnProto = Test.prototype

console.log(Object.keys(fnProto)) //['testMethod']
for (let k in fnProto) {
    console.log(k)              // 'testMethod'
}

而如果是class定义的话都将是空

class TestClass{
    testMethod() {}
}
const classProto = TestClass.prototype

console.log(Object.keys(classProto))  // []
for (let k in classProto) {
    console.log(k)             // 不会执行
}

我们可以看一下他们的描述符

Object.getOwnPropertyDescriptor(classProto, 'testMethod') 
// {value: ƒ, writable: true, enumerable: false, configurable: true}

而构造函数的描述符

Object.getOwnPropertyDescriptor(fnProto, 'testMethod') 
// {value: ƒ, writable: true, enumerable: true, configurable: true}

至此我们可以得出结论class定义的方法是不可枚举的。 那怎样才能遍历到class中的方法呢?

  1. 我们注意到虽然classProto的enumerable是false,但configurable为true。 所以我们可以直接
   Object.defineProperty(classProto, 'testMethod', {enumerable: true})
   console.log(Object.keys(classProto))  // ['testMethod']
  1. 还有一个很简单的方法Object.getOwnPropertyNames(),这也是我最后找到的答案
console.log(Object.getOwnPropertyNames(classProto)) // ['constructor', 'testMethod']

Object.getOwnPropertyNames返回一个数组包含对象自身拥有的可枚举和不可枚举属性。不过要注意一点,constructor也出现在了数组中,如果只需要方法属性,要做下过滤。

标题的答案其实很简单,只需要调用一个函数,但找寻这个答案的过程尝试了很多也了解了很多。

class和构造函数的不同在understandinges6有一个总结:

  • Class declarations, unlike function declarations, are not hoisted. Class declarations act like let declarations and so exist in the temporal dead zone until execution reaches the declaration.

  • 不同于function声明,class声明不存在作用域内的提升。class声明像let声明一样在执行到声明语句前会存在于temporal dead zone(TDZ)中。

  • All code inside of class declarations runs in strict mode automatically. There’s no way to opt-out of strict mode inside of classes.

  • class声明内的代码自动在严格模式下执行,逃不掉。。

  • All methods are non-enumerable. This is a significant change from custom types, where you need to use Object.defineProperty() to make a method non-enumerable.

  • 所有方法都是不可枚举的。正常自定义类型的话需要使用Object.defineProperty()让其不可枚举

  • All methods lack an internal [[Construct]] method and will throw an error if you try to call them with new.

-所有的方法都缺少内部[[Construct]]方法,如果你用new调用会报错

  • Calling the class constructor without new throws an error.

  • 不使用new调用class会报错

  • Attempting to overwrite the class name within a class method throws an error.

  • 在class方法内部重写class名会报错