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中的方法呢?
- 我们注意到虽然classProto的enumerable是false,但configurable为true。 所以我们可以直接
Object.defineProperty(classProto, 'testMethod', {enumerable: true})
console.log(Object.keys(classProto)) // ['testMethod']
- 还有一个很简单的方法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名会报错