JavaScript使用接口
在经典的Java面向对象语言中,可以用关键字interface来定义接口,用implement来实现接口,而JavaScript虽然也是面向对象语言,但是它并没有内置这些,不过由于JavaScript的灵活性,我们可以通过模拟来实现,方法是使用一个辅助类和辅助函数来协助完成这一过程。
代码
先把例子写出来,后面再讲解一些细节:
// 辅助类
var Interface = function(name,methods){
if(arguments.length != 2){
throw new Error("参数数量不对,期望传入两个参数,但是只传入了"+arguments.length+"个参数");
}
this.name = name;
this.methods = [];
for(var i = 0, len = methods.length; i < len; i++){
if(typeof methods[i] !== "string"){
throw new Error("期望传入的方法名是以字符串的格式类型,而不是"+ (typeof methods[i]) + "类型");
}
this.methods.push(methods[i]);
}
}
// 辅助函数
Interface.ensureImplements = function(object){
if(arguments.length < 2){
throw new Error("期望传入至少两个参数,这里仅传入"+arguments.length+"个参数");
}
for(var i = 1; i < arguments.length; i++){
var interface = arguments[i];
if(!(interface instanceof Interface)){
throw new Error(arguments[i] + "不是一个接口");
}
for(var j = 0, methodsLen = interface.methods.length; j < methodsLen; j++){
var method = interface.methods[j];
if(!object[method] || typeof object[method] !== "function"){
throw new Error("对象的方法 "+method+" 与接口 "+interface.name+" 定义的不一致");
}
}
}
}
//接口
var RobotMouth = new Interface('RobotMouth',['eat','speakChinese','speakEnglish']);
var RobotEar = new Interface('RobotEar',['listen']);
// 实现RobotMouth、RobotEar接口
// 构造函数
var Robot = function(){
};
Robot.prototype = {
// 实现RobotMouth接口
eat: function(){
console.log("I can eat");
},
speakChinese: function(){
console.log("I can speak Chinese");
},
speakEnglish: function(){
console.log("I can speak English");
},
// 实现RobotEar接口
listen: function(){
console.log("I can listening");
}
};
var miniRobot = new Robot();
function useRobot(robot){
Interface.ensureImplements(miniRobot,RobotMouth,RobotEar);
robot.eat();
robot.listen();
}
useRobot(miniRobot);
运行结果:
I can eat
I can listening
下面对这段代码进行讲解:
定义接口
//接口
var RobotMouth = new Interface('RobotMouth',['eat','speakChinese','speakEnglish']);
var RobotEar = new Interface('RobotEar',['listen']);
我们定义了两个接口,通过new Interface()来定义接口,在Interface这个函数中:
- 第一个参数是接口名称
- 第二个参数是一个数组,数组是元素是字符串的格式,里面分别是接口定义的方法
上述的代码,可理解为做下面的这样的定义:
/*
interface RobotMouth(){
function eat();
function speakChinese();
function speakEnglish();
}
interface RobotEar(){
function listen();
}
*/
现在我们来看一下Interface() 这个构造函数:
// 辅助类
var Interface = function(name,methods){
if(arguments.length != 2){
throw new Error("参数数量不对,期望传入两个参数,但是只传入了"+arguments.length+"个参数");
}
this.name = name;
this.methods = [];
for(var i = 0, len = methods.length; i < len; i++){
if(typeof methods[i] !== "string"){
throw new Error("期望传入的方法名是以字符串的格式类型,而不是"+ (typeof methods[i]) + "类型");
}
this.methods.push(methods[i]);
}
}
这个构造函数实现的是对传入的参数进行严格的校验,如果参数不对就会报错。这里首先是判断参数的个数,第二是判断传入的方法名是否是字符串的格式。
接口的实现
接口定义好后,通过一个类来实现,这里要注意的是,需要给出明确的注释,说明这个类实现的是哪个接口。
// 实现RobotMouth、RobotEar接口
// 构造函数
var Robot = function(){
};
Robot.prototype = {
// 实现RobotMouth接口
eat: function(){
console.log("I can eat");
},
speakChinese: function(){
console.log("I can speak Chinese");
},
speakEnglish: function(){
console.log("I can speak English");
},
// 实现RobotEar接口
listen: function(){
console.log("I can listening");
}
};
这里我们定义了一个Robot构造函数来实现以上两个接口,方法写在原型上,注意注释明确。
使用接口
var miniRobot = new Robot();
function useRobot(robot){
Interface.ensureImplements(miniRobot,RobotMouth,RobotEar);
robot.eat();
robot.listen();
}
useRobot(miniRobot);
首先我们创建了一个实例叫miniRobot,然后做为参数传入useRobot() 这个函数进行生产调用,在这个函数里的第一行代码Interface.ensureImplements(miniRobot,RobotMouth,RobotEar); 是对传入的miniRobot进行严格的校验,校验不通过会抛出异常。它接受的参数必须大于等于两个:
- 第一个参数是一个实现了接口的对象
- 第二个参数是对象的一个接口
- 第三个参数同上(若存在的话)
我们来看一下这段代码:
// 辅助函数
Interface.ensureImplements = function(object){
if(arguments.length < 2){
throw new Error("期望传入至少两个参数,这里仅传入"+arguments.length+"个参数");
}
for(var i = 1; i < arguments.length; i++){
var interface = arguments[i];
if(!(interface instanceof Interface)){
throw new Error(arguments[i] + "不是一个接口");
}
for(var j = 0, methodsLen = interface.methods.length; j < methodsLen; j++){
var method = interface.methods[j];
if(!object[method] || typeof object[method] !== "function"){
throw new Error("对象的方法 "+method+" 与接口 "+interface.name+" 定义的不一致");
}
}
}
}
首先对传入的参数进行校验,必须传入两个或以上的参数。
然后检查每个传入的接口是否已经定义,如果未定义,就抛出异常,表示不是一个接口。
然后对每个接口定义的方法进行遍历,与第一个参数(实现接口的对象)进行比较,如果对象没有实现接口的方法,那么这段代码throw new Error("对象的方法 "+method+" 与接口 "+interface.name+" 定义的不一致");就会抛出异常。
为什么使用接口
- 在大型项目中,有利于团队协作(比如分工等)
- 降低代码的耦合度,从某种意义上讲使代码更加灵活
- 提高开发效率,通过接口的定义可以先“用上”接口,等接口被实现之后即可得到验证,而不需要进行等待
JavaScript使用接口的更多相关文章
- JavaScript fetch接口
JavaScript fetch接口 如果看网上的fetch教程,会首先对比XMLHttpRequest和fetch的优劣,然后引出一堆看了很快会忘记的内容(本人记性不好).因此,我写一篇关于fetc ...
- 读书笔记之 - javascript 设计模式 - 接口、封装和链式调用
javascript 采用设计模式主要有下面的三方面原因: 可维护性:设计模式有助于降低模块之间的耦合程度.这使代码进行重构和换用不同的模块变得容易,也使程序员在大型项目中合作变得容易. 沟通:设计模 ...
- JavaScript设计模式接口
JavaScript中实现接口的方法有三种: 第一种,使用注释的方法实现接口 特点:(1)最简单,但是功能最弱(2)利用 interface和 implement"文字"(3)把他 ...
- JavaScript实现接口的三种经典方式
/* 接口:提供一种说明一个对象应该有哪些方法的手段 js中有三种方式实现接口: 1 注释描述接口 2 属性检测接口 3 鸭式辨型接口 */ /* 1 注释描述接口: 不推荐 优点: 利用注解,给出参 ...
- javascript 实现 接口编程
// Constructor. var Interface = function (name, methods) { if (arguments.length != 2) { throw new Er ...
- 《JavaScript设计模式》笔记之第一、二章:富有表现力的JavaScript 和 接口
第一章 创建一个类 方法一: var Anim = function() { ... }; Anim.prototype.start = functi ...
- javascript鸭式辩型法实现接口
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...
- javascript设计模式开篇:Javascript 接口的实现
javascript语言不像java. c#. c++等面向对象语言那样有完备的接口支持,在javascript中,接口的实现有三种方式,分别为注释描述.属性检查.鸭式变形.注释描述实现起来最为简单, ...
- 深入理解JavaScript系列(21):S.O.L.I.D五大原则之接口隔离原则ISP
前言 本章我们要讲解的是S.O.L.I.D五大原则JavaScript语言实现的第4篇,接口隔离原则ISP(The Interface Segregation Principle). 英文原文:htt ...
随机推荐
- win8.1系统的安装方法详细图解教程
win8.1系统的安装方法详细图解教程 关于win8.1系统的安装其实很简单 但是有的童鞋还不回 所以今天就抽空做了个详细的图解教程, 安装win8.1系统最好用U盘安装,这样最方便简单 而且系统安装 ...
- Socket异步通讯
1.可以通过多线程来解决(一会补上) 2.Socket在tcp/udp两种通信协议下的异步通信: 基于TCP的异步通信: BeginAccept方法和endeaccept方法 包含在System.Ne ...
- A Quick Introduction to Linux Policy Routing
A Quick Introduction to Linux Policy Routing 29 May 2013 In this post, I’m going to introduce you to ...
- 移动端框架篇-控制父容器的滑屏框架-slip.js
设计滑屏框架的办法一般有2种 控制父容器法 控制子容器法 这个算是控制父容器法 通过控制父容器的transform: translateY或margin-top或top的值来上下滑动页面,每次的位移的 ...
- nyoj 623 A*B Problem II(矩阵)
A*B Problem II 时间限制:1000 ms | 内存限制:65535 KB 难度:1 描述 ACM的C++同学有好多作业要做,最头痛莫过于线性代数了,因为每次做到矩阵相乘的时候,大 ...
- linuxmint 17安装qt5.3.1
从官方网站上下载的安装包,双击安装即可. 新建项目编译时,出现错误:cannot find -lGL 解决的方法:安装libgl1-mesa-dev,当然在安装时会安装其他的一些依赖包 在命令行中输入 ...
- 如何修改 Total commander 配置文件的路径
在官方主页 http://www.ghisler.com/tools.htm#other 上提供了一个名为 INIreloc.exe 的小程序,它可以变更ini文件的保存位置.
- CSS书写规范、命名规范、网易CSS框架NEC
网易CSS框架NEC:http://nec.netease.com/ NEC框架的CSS规范: CSS规范 - 分类方法 CSS规范 - 命名规则 CSS规范 - 代码格式 CSS规范 - 优化方案 ...
- jvm指令调试
监控GC的工具分为2种:命令行工具和图形工具: 常用的命令行工具有: 注:下面的命令都在JAVA_HOME/bin中,是java自带的命令.如果您发现无法使用,请直接进入Java安装目录调用或者先设置 ...
- Android多种进度条使用详解
在这里,总结一下loading进度条的使用简单总结一下. 一.说起进度条,必须说说条形进度条,经常都会使用到嘛,特别是下载文件进度等等,还有像腾讯QQ安装进度条一样,有个进度总给人良好的用户体验. 先 ...