用JavaScript实现接口
JavaScript并不支持接口(interface),然而在构建大型框架/库的时候,我们很需要想办法实现接口的特性:
- 实现接口的类必须实现了接口中的方法;
- 有办法检测到该类的实例的类型,并且这个类型和接口(约定的)类型值相等。
01.TypeScript的实现
由于JavaScript没有接口,因此,我将向你展示TypeScript如何实现此目的,因为TypeScript补全了JavaScript面向对象编程的能力,以和JavaScript面向原型的一个分支领域区别开来。
interface ShapeInterface {
area(): number
}
class Circle implements ShapeInterface {
let radius: number = 0
constructor (r: number) {
this.radius = r
}
public area(): number {
return MATH.PI * MATH.pow(this.radius, 2)
}
}
在上面的示例中,展示了如何在TypeScript中实现此目标,但是TypeScript在后台将代码编译为纯JavaScript,而在已编译的代码中,由于JavaScript没有接口,因此也竟然没有给出接口有关的表现形式。真是扫兴啊!
02.JavaScript的实现
那么在JavaScript缺乏接口的情况下,我们如何实现这一目标呢?
通过函数组合 可以实现。
首先,我们创建shapeInterface
工厂函数,因为我们在谈论接口,所以我们的shapeInterface
将使用函数组合出像接口一样抽象体。
什么是工厂函数?
在JavaScript中,函数若返回一个对象,且被返回的对象既不是构造函数、也不是某一个类,那么这该函数被称作工厂函数。
const shapeInterface = (state) => ({
type: 'shapeInterface',
area(){
if(state.area && typeof state.area === "function")
return state.area(state);
else
throw new Error("必须实现接口shapeInterface的方法area");
}
})
然后我们让正方形(square)工厂函数实现上面的接口。
const square = (length) => {
const proto = {
length,
type : 'Square',
area : (args) => Math.pow(args.length, 2)
}
const basics = shapeInterface(proto)
const composite = Object.assign({}, basics)
return Object.assign(Object.create(composite), {length})
}
接着调用工厂函数square
后,结果应该是下面这样的:
const s = square(5)
console.log('OBJ\n', s)
console.log('PROTO\n', Object.getPrototypeOf(s))
s.area()
// 输出
//>> OBJ
//>> { length: 5 }
//>> PROTO
//>> { type: 'shapeInterface', area: [Function: area] }
//>> 25
如此一来,我们可试着做一个产品经理要求的功能:计算面积之和的。其间可以检测具体的对象否有没有实现接口:
//计算面积之和
sum() {
const area = []
for (shape of this.shapes) {
//用Object.getPrototypeOf来检测类型
if (Object.getPrototypeOf(shape).type === 'shapeInterface') {
area.push(shape.area())
} else {
throw new Error('该对象不是接口shapeInterface的实例')
}
}
return area.reduce((v, c) => c += v, 0)
}
03.结语
最后再次说一下,由于JavaScript不支持强类型语言之类的接口,上面的示例演示了我们如何模拟它,并不能十分完美的实现接口的各种特性。这也许是语言本身的局限,也有待你我探索。
当前页面是本站的「Google AMP」版。查看和发表评论请点击:完整版 »