JavaScript面向对象中接口实现方法详解


Posted in Javascript onJuly 24, 2019

本文实例讲述了JavaScript面向对象中接口实现方法。分享给大家供大家参考,具体如下:

接口是面向对象编程的基础,它是一组包含了函数型方法的数据结构,与类一样,都是编程语言中比较抽象的概念。比如生活中的接口,机顶盒,人们利用它来实现收看不同频道和信号的节目,它犹如对不同类型的信息进行集合和封装的设备,最后把各种不同类型的信息转换为电视能够识别的信息。在编程语言中的接口,实际上是不同类的封装并提供统一的外部联系通道,这样其他对象就可以利用接口来调用不同类的成员了。

——整理自《jQuery开发从入门到精通》

接口的概念

构造函数(类)是具体的实现,接口是类的约定。API接口(应用程序接口)、人机交互接口、电源接口、USB接口等虽然用途不同,功能各异,但是都包含一个共同的特性:约定、规范。可以说,接口就是一张契约和合同,它约定了设计者和使用者都必须遵循的要求。

接口承诺了具体类应该事先的功能。

举一个很有必要的例子,在java中实现接口,比如下面的代码:

interface Base{
 void function1();
 void function2();
 void function3();
}

Base接口承诺了3个基本功能:function1()、function2()、function3()。这个接口就像是一份合同,在甲方(调用类的用户)和乙方(定义类的开发人员)之间约定。

乙方负责实现接口约定的功能。功能的实现就是所谓的类。如下实例:

class App implements Base  // 定义一个App类,用这个类来实现接口Base

类App将遵照接口的约定。专业来说就是,应用类App继承Base接口类。

它的具体实现如下:

class App implements Base{
 void function1(){
  System.out.println("I am fun1");
 }
 void function2(){
  System.out.println("I am fun2");
 }
 void function3(){
  System.out.println("I am fun3");
 }
}

这样,乙方实现了这个接口,而甲方也应该来按照接口的约定去使用类App就行了。

所以说,接口(interface)和类(class),实际上都是相同的数据结构。

在接口中可以声明属性,方法,事件,类型,但不能声明变量,且不能设置被声明成员的具体值(功能实现)。

也就是说,接口只能定义成员,不能给定义的成员赋值。而接口作为它的继承类或派生类的约定,继承类或派生类共同完成接口属性、方法、事件、类型的实现。在接口和实现类之间,不管是方法名还是属性调用顺序上都应保持一致。

接口的目的就是约束编码,促使代码规范,对于强类型语言是必须的,也是非常重要的环节。但是对于JavaScript弱类型语言来说,严格的类型检查会束缚JavaScript的灵活性。很多前端开发人员根本不用接口,但不会影响脚本的设计。

使用接口的好处:降低对象间的耦合度,提高代码的灵活性。学会使用接口,能够让手中的函数变得灵巧,这在大型开发中是很重要的。

对于JavaScript来说,本身不支持接口功能,没有提供内置方法。但是人工设计一个额外的接口程序,又会对程序的性能产生影响。项目越大,这种开销越大。所以,用不用接口可以遵循两个条件:

① 项目大小,如果是一个框架,使用接口在一定程度上会提高程序的性能。如果是简单的应用,就不必使用接口了。

② 如果对JavaScript接口比较熟练,多用接口也可以,如果担心过多使用接口影响性能,则可以在考虑产品发布前,清除接口功能模块,或者设置接口的执行条件。防止它被频繁执行,影响性能。

接口的实现

JavaScript中并不支持接口,但是我们可以模仿其他语言,来定义接口。

下面来规划接口结构的设计和检测功能的实现:

(1) 设计一个接口辅助的类结构,这个构造函数相当于一个过滤器,用于在接口实例化过程中,检测初始化参数是否合法。如果符合接口设计标准,则把第2个参数中每个方法名和参数个数以数组元素的形式输入接口内部属性methods。在输入前分别检测每个参数类型是否符合规定。同时检查参数是否存在残缺,并即时以0补齐参数。

function Interface(name,methods){ // 接口辅助类,参数包括接口实例的名称和方法集
 if(arguments.length!=2){ // 如果参数个数不等于2,抛出异常。
  throw new Error('标准接口约定,需要两个参数');
 }
 this.name = name; // 存储第一个参数值,实例化后就是接口实例的名称
 this.methods = []; // 接口实例的方法存储器
 if(methods.length < 1){ // 如果第二个参数的元素个数为0,说明是空数组,抛出异常。
  throw new Error('接口的第二个参数不能为空');
 }
 for(var i = 0; i < methods.length; i++){ // 开始对第2个参数的元素进行遍历检测
  var item = methods[i];
  if(typeof item[0] !== 'string') { // 如果第二个参数的第一个元素不是string类型,抛出异常
   throw new Error("接口约定的第一个参数应为字符串");
  }
  if(item[1]&&typeof item[1] !== 'number'){ // 如果第二个参数有第二个元素,且第二个元素不是number类型,抛出异常
   throw new Error('接口约定的第个参数应为数值');
  }
  if(item.length == 1){ // 如果第二个参数只有一个元素,那么手动给它添加第二个元素 0
   item[1] = 0;
  }
  this.methods.push(item); // 把符合规定的方法存储到数组存储器中。
 }
}

(2) 为接口辅助类 Interface 定义一个方法 implements,该方法将检测实现类是否符合接口实例的约定。它至少包含两个参数,第1个参数o表示实现类,第2个参数及其后面的参数表示该类将要实现的接口标准。也就是说,可以为一个类指定多个接口约定,这样就可以更灵活的分类设计接口实例。然后遍历第二个及其后面的所有参数,在循环结构中,先洁厕接口是否为接口标准的实例,否则就会抛出异常。再从接口实例的方法存储器中逐一读取方法名,填入类中来验证类的方法是否符合接口实例设置的标准,验证包括方法名、function类型和参数个数。如果有问题,立即抛出异常。

Interface.implements = function(o){ // 用于检测类方法是否符合接口实例的约定 ,此处的o,将来会是类中的this
 if(arguments.length<2){ // 检测该方法传递的数值是否符合规定
  throw new Error("接口约定类应包含至少两个参数。");
 }
 for(var i=1;i<arguments.length; i++){ // 遍历检测类所遵循的实例是否合法
  var interface = arguments[i]; // 这里interface表示接口的实例对象。
  if(interface.constructor !== Interface){
   throw new Error('从第2个以上的参数必须为接口实例');
  }
  for(var j=0;j<interface.methods.length;j++){ // 检测类方法是否符合接口实例的约定
   var method = interface.methods[j][0];
   if(!o[method] || typeof o[method] !== 'function' || o[method].length!==interface.methods[j][1]) {
    throw new Error("该实现类没能履行" + interface.name + "接口方法" + method + "约定");
   }
  }
 }
}

(3) 实例化接口标准,Interface 接口仅仅是个构造函数,也就是个框架协议,还没有制定类应该遵循的具体标准。框架协议中,已经设计好了监测逻辑,一旦实例化接口,并指明类应遵守的约定,那么应用该标准的实例的类就必须准守。下面根据Interface接口标准定义了6个具体的接口实例。

// 设置接口的不同实现实例
var Get = new Interface("Get",[["get",0]]);
var Set = new Interface("Set",[["set",1]]);
var Saying = new Interface("Saying",[["saying",1]]);
var Base = new Interface("Base",[["get",0],["set",1]]);
var Base1 = new Interface("Base1",[["set",1],["get",0]]);
var Base2 = new Interface("Base2",[["get",0],["set",1],["saying",1]]);

(4) 在类中定义应该实现的标准,即类应该遵循的接口约定。

// 创建一个木驴类
function Neddy(){
 this.name = '';
 Interface.implements(this,Base,Get,Set); // 让木驴类实现接口的实例,可以指定多个,也可以只有一个。
}
// 按照接口实例来定义 两个方法get,set
Neddy.prototype.get = function(){
 return this.name;
}
Neddy.prototype.set = function(name){
 this.name = name;
}

(5) 在类中设置了多个接口实例,我们来进行检测

// 检测接口实现
var neddy = new Neddy();
neddy.set("Testing");
console.log(neddy.get()); // Testing

成功完成接口的应用,这里,如果在Neddy类中,我们让它实现的接口实例和 Neddy.prototype中给类定义的方法不统一,或者接口与接口之间有冲突,就会抛出异常。比如我们可以修改Neddy中的接口实现,再给它添加一个接口实例Base2,就会报异常,因为我们没有按照接口的协议,给Neddy添加saying()方法。

上面的举例只是用js来模拟实现接口功能,在实际开发中,我们需要根据不同的需求,开发不同的接口。

扩展知识 :

检测函数的参数列表一般有三种形式

  • ① arguments.callee.length
  • ② 函数名.length
  • ③ arguments.length

其中 ① 和 ② 是一样的,③ 视具体情况而定。
一般函数声明式的定义有个默认属性name继承自Object ,举例如下:

function fn(x,y){
  console.log(fn.name); // fn
  console.log(arguments.callee.name); // fn
  console.log(fn.length); // 2
  console.log(arguments.callee.length); // 2
  console.log(arguments.length); // 视具体情况而定
}
fn(1,2,3); // 分别输出 fn fn 2 2 3

为了说明上面接口检测参数长度 o[method].length  的问题 ,举例如下:

function A(){}
A.prototype.say = function (x,y,z,o) {}
var a = new A();
console.log(a['say'].length); // 4

希望本文所述对大家JavaScript程序设计有所帮助。

Javascript 相关文章推荐
javascript模仿msgbox提示效果代码
Jun 10 Javascript
jquery ajax 登录验证实现代码
Sep 23 Javascript
js 中将多个逗号替换为一个逗号的代码
Jun 07 Javascript
JavaScript对表格或元素按文本,数字或日期排序的方法
May 26 Javascript
JavaScript中用getDate()方法返回指定日期的教程
Jun 09 Javascript
详解Vue中一种简易路由传参办法
Sep 15 Javascript
详解vue2.0监听属性的使用心得及搭配计算属性的使用
Jul 18 Javascript
微信小程序封装分享与分销功能过程解析
Aug 13 Javascript
Vue打包后访问静态资源路径问题
Nov 08 Javascript
JS+DIV实现拖动效果
Feb 11 Javascript
JS实现简单贪吃蛇小游戏
Oct 28 Javascript
Vue ​v-model相关知识总结
Jan 28 Vue.js
IE11下处理Promise及Vue的单项数据流问题
Jul 24 #Javascript
微信小程序如何引用外部js,外部样式,公共页面模板
Jul 23 #Javascript
详解Vue中的基本语法和常用指令
Jul 23 #Javascript
js如何获取访问IP、地区、当前操作浏览器
Jul 23 #Javascript
node.js express框架简介与实现
Jul 23 #Javascript
js微信分享接口调用详解
Jul 23 #Javascript
详解vue-cli项目开发/生产环境代理实现跨域请求
Jul 23 #Javascript
You might like
PHP压缩html网页代码(清除空格,换行符,制表符,注释标记)
2012/04/02 PHP
PHP的图像处理实例小结【文字水印、图片水印、压缩图像等】
2019/12/20 PHP
JQuery UI的拖拽功能实现方法小结
2012/03/14 Javascript
使用jQuery同时控制四张图片的伸缩实现代码
2013/04/19 Javascript
jquery click([data],fn)使用方法实例介绍
2013/07/08 Javascript
js验证真实姓名与身份证号是否匹配
2015/10/13 Javascript
angularJS 如何读写缓冲的方法(推荐)
2016/08/06 Javascript
JavaScript中最容易混淆的作用域、提升、闭包知识详解(推荐)
2016/09/05 Javascript
jQuery插件FusionCharts绘制2D环饼图效果示例【附demo源码】
2017/04/10 jQuery
基于Vue实现后台系统权限控制的示例代码
2017/08/29 Javascript
基于vue-resource jsonp跨域问题的解决方法
2018/02/03 Javascript
微信小程序chooseImage的用法(从本地相册选择图片或使用相机拍照)
2018/08/22 Javascript
vue-cli 3.0 版本与3.0以下版本在搭建项目时的区别详解
2018/12/11 Javascript
vue 子组件watch监听不到prop的解决
2020/08/09 Javascript
实例Python处理XML文件的方法
2015/08/31 Python
编写Python爬虫抓取暴走漫画上gif图片的实例分享
2016/04/20 Python
win10 64bit下python NLTK安装教程
2018/09/19 Python
Python实现将多个空格换为一个空格.md的方法
2018/12/20 Python
详解如何从TensorFlow的mnist数据集导出手写体数字图片
2019/08/05 Python
python pycharm的安装及其使用
2019/10/11 Python
python 8种必备的gui库
2020/08/27 Python
python批量生成条形码的示例
2020/10/10 Python
python中使用np.delete()的实例方法
2021/02/01 Python
亚马逊西班牙购物网站:amazon西班牙
2017/03/06 全球购物
芬兰设计商店美国:Finnish Design Shop US
2019/03/25 全球购物
欧克利英国官网:Oakley英国
2019/08/24 全球购物
什么是就业协议书
2014/04/17 职场文书
《与朱元思书》的教学反思
2014/04/17 职场文书
明星员工获奖感言
2014/08/14 职场文书
党员群众路线对照检查材料思想汇报
2014/09/17 职场文书
交通事故协议书范本
2014/11/18 职场文书
2015年简历自我评价范文
2015/03/11 职场文书
2015年仓库管理工作总结
2015/05/25 职场文书
使用pytorch实现线性回归
2021/04/11 Python
java协程框架quasar和kotlin中的协程对比分析
2022/02/24 Java/Android
一文解答什么是MySQL的回表
2022/08/05 MySQL