用JavaScript实现接口

2021-11-16T09:36:25

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不支持强类型语言之类的接口,上面的示例演示了我们如何模拟它,并不能十分完美的实现接口的各种特性。这也许是语言本身的局限,也有待你我探索。

当前页面是本站的「Baidu MIP」版。发表评论请点击:完整版 »