在这篇博客文章中,我将介绍接口的概念以及它们在动态语言中的用法。 我还将使用库Implement.js将概念引入JavaScript,并向您展示如何从接口中获取一些额外的实用程序。
什么是接口?
Google将界面定义为“两个系统,主题,组织等相遇并交互的点”,并且该定义对于编程中的界面也适用。 在软件开发中,接口是在对象上强制实施特定属性的结构-在大多数语言中,该对象是类。
这是Java接口的示例:
在上面的示例中, Car
接口描述了一个类,该类具有两个没有返回类型的方法,两个方法都带有一个整数参数。 每个函数的实现细节都由类决定,这就是为什么方法都没有主体的原因。 为了确保一个类实现Car
接口,我们使用implements
关键字:
JavaScript中的接口
接口在JavaScript中不是问题,反正不是。 JavaScript是一种动态语言,这种语言经常更改类型,以至于开发人员甚至都可能没有意识到,因此人们认为不需要将接口添加到JavaScript所基于的ECMAScript标准中。
但是,JavaScript已作为Node.js形式的后端语言大量发展,随之而来的是不同的需求和不同的人群,他们可能有不同的见解。 为了增加这一点,语言正迅速成为前端工具; 到目前为止,许多开发人员将以JSX的形式在.js文件中编写绝大多数HTML。
因此,随着语言逐渐担当更多的角色,那么确保我们最关键的数据结构之一就是我们所期望的是很有帮助的。 JavaScript可能具有class
关键字,但实际上这只是一个未实例化的构造函数,而一旦调用它就只是一个对象。 对象无处不在,因此有时确保它们与特定形状匹配是有益的。
最近在工作中,我发现一种情况,开发人员期望作为API响应的一部分返回的属性为true
但是却变为"true"
,从而导致错误。 一个简单的错误,如果有了接口,也可以避免。
但是,等等,还有更多!
经过一些小的修改的界面可用于重塑对象。 想象一下实现一个“严格”接口,其中不允许在接口之外的任何属性,我们可以删除或重命名这些属性,如果遇到它们,甚至会抛出错误。
因此,现在我们有了一个界面,该界面将告诉我们何时缺少某些属性,何时有意外属性,或者属性的类型是否不是我们期望的。 这增加了其他可能性,例如重构来自API的响应,同时在接口的标准行为之上增加了额外的安全性。 如果我们有接口抛出错误,也可以在单元测试中使用它们。
Implement.js
Implement.js是一个尝试将接口引入JavaScript的库。 这个想法很简单:定义一个接口,定义其属性的类型,并使用它来确保对象就是您期望的对象。
设定
首先安装软件包:
npm install implement-js
接下来,创建一个.js文件并导入implement
, Interface
和type
:
我们的第一个界面
要创建一个接口,只需调用Interface
并传入一个字符串作为您的接口名称-不建议这样做,但是如果您省略该名称,则会生成一个唯一的ID。 这将返回一个函数,该函数接受一个属性为所有type
对象的对象,还可以传递第二个参数,并带有显示警告,抛出错误,删除或重命名属性,确保仅存在接口属性或扩展属性的选项。现有Interface
。
这是描述汽车的界面:
它具有一个应该为number类型的seats
属性,一个名为passengers的数组,其中包含必须自己实现Passenger
接口的对象,并且它包含一个beep
属性,该属性应为一个函数。 该error
和strict
选项已被设置为true,这意味着错误将接口的属性丢失时,当被发现, 但接口上的财产被抛出而还。
实施我们的界面
现在我们要实现我们的接口,在一个简单的示例中,我们将使用对象文字创建一个对象,并查看我们是否能够实现我们的接口。
首先,我们创建一个Ford
对象,然后尝试在Car
接口上实现该对象:
正如我们从上面的评论中看到的那样,这引发了错误。 让我们回顾一下Car
界面:
我们可以看到,虽然所有属性都存在,但严格模式也适用,这意味着附加属性fuelType
会引发错误。 此外,尽管我们拥有passengers
财产,但它不是一个数组。
为了正确地实现该接口,除去fuelType
和改变的值passengers
,以便它是含有实现该对象的数组Passenger
接口:
“但是JavaScript并不是一种面向对象的语言!”
的确,尽管接口通常与面向对象的语言相关联,并且JavaScript是使用原型继承的多范式语言,但是接口仍然非常有用。
例如,使用implement-js
我们可以轻松地重构API响应,同时确保它不会偏离我们的期望。 这是与redux-thunk
结合使用的示例:
首先,我们将TwitterUser
接口定义为具有twitterId
和twitterUsername
属性的对象,该接口扩展了User
接口。 trim
是真实的,这意味着我们将丢弃TwitterUser
界面上未描述的任何属性。 由于我们的API以不友好的格式返回属性,因此我们已将属性从twitter_username
和twitter_id
重命名为其自身的驼峰版本。
接下来,我们使用redux-thunk
定义一个异步操作,该操作触发一个API调用,并且我们使用TwitterUser
接口丢弃不需要的属性,并确保它以正确的类型实现了我们期望的属性。 如果您想让动作创建者保持纯净或不使用redux-thunk
,则可能需要检查twitterService.getUser
内部的接口并返回结果。
注意:扩展接口时不会继承选项
单元测试也是使用接口的合适场所:
综上所述
我们已经看到了接口如何在JavaScript中有用:尽管它是一种高度动态的语言,但检查对象的形状以及它的属性是否是特定的数据类型为我们提供了额外的安全保障,否则我们将无法继续工作。 通过建立接口的概念并使用implement-js
我们还可以在增加的安全性之上获得更多的实用程序。
推特: @josh_jahans
From: https://hackernoon.com/implementing-interfaces-in-javascript-with-implement-js-8746838f8caa