javascript解耦,解耦的定义
如何封装常用的JS方法
1、JS封装就是尽量把使用的方式简单化,内部逻辑和使用解耦。通俗的说就是使用的时候只需要知道参数和返回值,其他条件尽量不要使用人员进行设置。
创新互联公司是一家专注于成都网站设计、网站建设与策划设计,荔波网站建设哪家好?创新互联公司做网站,专注于网站建设十多年,网设计领域的专业建站公司;建站业务涵盖:荔波等地区。荔波做网站价格咨询:18982081108
2、JS封装的方法有函数方式、对象的方式、闭包的方式。
举例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
1)函数方式
function kk(a,b){
内部对a,b怎么处理就不需要关心了
}
2)对象方式
function kk(a,b){
this.x = a;
this.y = b;
}
var k = new kk(1,2);//通过面向对象的方式
alert(k.x);
3)闭包方式
function kk(a,b){
var k = 1;
return function tt(){
k++;
}
}
var u = kk(1,2);
u();//闭包实现累加
u();//闭包实现累加
如何组织大型JavaScript应用中的代码
以下为CSDN编译:地板上堆放的衣服首先,我们来看看angular-seed,它是AngularJS应用开发的官方入门项目,其文件结构是这样的:css/img/js/app.jscontrollers.jsdirectives.jsfilters.jsservices.jslib/partials/看起来就像是把衣服按类型堆在地板上,一堆袜子、一堆内衣、一堆衬衫等等。你知道拐角的那堆袜子里有今天要穿的黑色羊毛袜,但你仍需要花上一段时间来寻找。这种组织方式很凌乱。一旦你的代码中存在6、7个甚至更多的控制器或者服务,文件管理就会变得难以处理:很难找到想要寻找的对象,源代码控制中的文件也变更集变得难懂。袜子抽屉常见的JavaScript文件结构还有另一种形式,即按原型将文件分类。我们继续用整理衣服来比喻:现在我们买了有很多抽屉的衣柜,打算将袜子放在其中一个抽屉里,内衣放在另一个抽屉,再把衬衫整齐地叠在第三个抽屉……想象一下,我们正在开发一个简单的电子商务网站,包括登陆流程、产品目录以及购物车UI。同样,我们将文件分为以下几个原型:models(业务逻辑和状态)、controllers以及services(HTTP/JSON端点加密),而按照Angular默认那样非笼统地归到“service”架构。因此我们的JavaScript目录变成了这样:controllers/LoginController.jsRegistrationController.jsProductDetailController.jsSearchResultsController.jsdirectives.jsfilters.jsmodels/CartModel.jsProductModel.jsSearchResultsModel.jsUserModel.jsservices/CartService.jsUserService.jsProductService.js不错,现在已经可以通过树形文件目录或者IDE快捷键更方便地查找文件了,源代码控制中的变更集(changeset)也能够清楚地描述文件修改记录。虽然已经获得了极大的改进,但是仍有一定的局限性。想象一下,你现在正在办公室,突然发现明天有个商务出差,需要几套干洗的衣服,因此给家里打电话告诉另一半把黑色和蓝色的西装交给清洁工,还有黑纹领带配灰色衬衫、白衬衫配纯黄领带。如果你的另一半并不熟悉衣柜,又该如何从三条黄色的领带中挑出你的正确需求?模块化希望衣服的比喻没有让你觉得过于陈旧,下面举一个实例:你的搭档是新来的开发者,他被要求去修补这个复杂应用中的一处bug。他扫过这些文件夹,看到了controllers、models、services等文件夹整齐地排列着,但是他仍然不清楚对象间的依赖关系。处于某些原因,他希望能够重用部分代码,这需要从各个文件夹中搜集相关文件,而且常常会遗漏某些文件夹中的对象。信或不信,你确实很少会在新项目中重用很多代码,但你很可能需要重用登陆系统这样的整个模块。所以,是不是按功能划分文件会更好?下面的文件结构是以功能划分后的应用结构:cart/CartModel.jsCartService.jscommon/directives.jsfilters.jsproduct/search/SearchResultsController.jsSearchResultsModel.jsProductDetailController.jsProductModel.jsProductService.jsuser/LoginController.jsRegistrationController.jsUserModel.jsUserService.js虽然现实世界中有空间限制,难以随意整理服装,但是编程中类似的处理却是零成本的。现在即使是新来的开发者也能通过顶级文件夹的命名理解应用的功能,相同文件夹下的文件会存在互相依赖等关系,而且仅仅通过浏览文件组织结构就能轻易理解登录、注册等功能的原理。新的项目也可以通过复制粘贴来重用其中的代码了。使用AngularJS我们可以进一步将相关代码组织为模块:var userModule = angular.module('userModule',[]); userModule.factory('userService', ['$http', function($http) { return new UserService($http); }]); userModule.factory('userModel', ['userService', function(userService) { return new UserModel(userService); }]); userModule.controller('loginController', ['$scope', 'userModel', LoginController]); userModule.controller('registrationController', ['$scope', 'userModel', RegistrationController]);如果我们将UserModule.js文件放到user文件夹,它就成了这个模块中使用到的对象的“manifest”,这也是适合RequireJS或者Browserify中放置某些加载指令的地方如何处理通用代码每个应用都会有某些代码广泛使用在多个模块中,我们常常使用名为“commom”或者“shared”的文件夹来存放这些功能代码。又该如何处理这些通用代码呢?如果模块中的对象需要直接访问几个“通用”对象,为这些对象提供几个Facade(外观模式)。这有助于减少每个对象的依赖者,而过多的关联对象通常意味着糟糕的代码结构。如果“通用”模块变得过于庞大,你需要将它按功能领域细分为多个子模块。确保每个应用模块只使用它需要的“通用”模块,这即是SOLID中“接口隔离原则”的变种。在根范围($rootScope)添加实体,这样子范围也可以使用,适合多个控制器都依赖同一个对象(比如“PermissionsModel”)的情况。在解耦两个不明确互相引用的组件时,请使用事件。Angular中Scope对象的$emit、$broadcast以及$on方法使得这种方式变得现实。控制器能够触发一个事件来执行某些动作,然后再动作结束后收到相应地通知。
前端设计模式之责任链模式
责任链模式
什么是责任链模式
责任链(Chain of Responsibility)模式的定义:为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。(此处引自 gof 设计模式)
在责任链模式中,客户只需要将请求发送到责任链上即可,无须关心请求的处理细节和请求的传递过程,所以责任链将请求的发送者和请求的处理者解耦了。
责任链模式是一种对象行为型模式,其主要优点如下:
1.降低了对象之间的耦合度。该模式使得一个对象无须知道到底是哪一个对象处理其请求以及链的结构,发送者和接收者也无须拥有对方的明确信息。
2.增强了系统的可扩展性。可以根据需要增加新的请求处理类,满足开闭原则。
3.增强了给对象指派职责的灵活性。当工作流程发生变化,可以动态地改变链内的成员或者调动它们的次序,也可动态地新增或者删除责任。
4.责任链简化了对象之间的连接。每个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的 if 或者 if···else 语句。
5.责任分担。每个类只需要处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。
其主要缺点如下。
1.不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。
2.对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
3.职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。
其他说明
责任链模式,总的一个核心就是请求者不必知道是谁哪个节点对象处理的请求,由于处理请求的可以在不同对象下处理,所以请求者跟接受者是解耦的。
纯的责任链:要求请求在这些对象链中 必须被处理 ,而且一个节点处理对象,要么只处理请求,要么把请求转发给下个节点对象处理;
不纯的责任链:要求在责任链里 **不一定会有处理结构 **,而且一个节点对象,即可以处理部分请求,并把请求再转发下个节点处理;
javascript 中介者模式
责任链模式对前端开发来说可能有点陌生,但是看了前面的描述又感觉似曾相识
实际上 express、redux 里的 middleware 都可以简单理解为责任链模式的运用
要实现中间件模式,最重要的实现细节是:
1.可以通过调用 use() 函数来注册新的中间件
2.当接收到需要处理的新数据时,注册的中间件在执行流程中被依次调用。每个中间件都接受上一个中间件的执行结果作为输入值
3.每个中间件都可以停止数据的进一步处理,只需要简单地不调用它的回调函数或者将错误传递给回调函数。当发生错误时,通常会触发执行另一个专门处理错误的中间件
项目实战
通用中间件开发
通用中间件使用 ajax
如上我们在发送请求之前加入了类型转换、数据校验,将数据的业务处理使用中间件模式剥离,使得处理过程模块化,维护性提升。
中间件升级-事件回调
每个中间件的过程都是不可控制的,全部都交由中间类去统一调用,我们可以加入事件回调,方便我们在中间件处理过程中拥有额外的逻辑能力
将上述的使用方法再改造一下,方便实际业务中使用
上述的项目实例是采用 ajax 来演示,实际通用的中间件类,可以在业务中将一些 **流程化执行的任务 **拆分出来,例如表单验证、多重条件判断等等
多种条件判断
将流程化执行的多种条件判断通过中间件解耦,可以使得条件判断方法更加清晰。一般当你需要使用中介者来改造业务逻辑的时候,前端的项目确实有点复杂了。
现在STAR现在是在腾讯课堂里面分享自己的经验,感谢兴趣的朋友可以加Q群:1146649671
中获取STAR在腾讯课堂分享的链接,还可以获取学习资料 面试文档等
Javascript如何实现接口?
在javascript中并没有原生的创建或者实现接口的方式,或者判定一个类型是否实现了某个接口,我们只能利用js的灵活性的特点,模拟接口。
在javascript中实现接口有三种方式:注释描述、属性验证、鸭子模型。
note:因为我看的是英文书,翻译水平有限,不知道有些词汇如何翻译,大家只能领会精神了。
1. 注释描述 (Describing Interfaces with Comments)
例子:
复制代码 代码如下:
/*
interface Composite {
function add(child);
function remove(child);
function getChild(index);
}
interface FormItem {
function save();
}
*/
var CompositeForm = function(id, method, action) { // implements Composite, FormItem
...
};
//Implement the Composite interface.
CompositeForm.prototype.add = function(child) {
...
};
CompositeForm.prototype.remove = function(child) {
...
};
CompositeForm.prototype.getChild = function(index) {
...
};
// Implement the FormItem interface.
CompositeForm.prototype.save = function() {
...
};
模拟其他面向对象语言,使用interface 和 implements关键字,但是需要将他们注释起来,这样就不会有语法错误。
这样做的目的,只是为了告诉其他编程人员,这些类需要实现什么方法,需要在编程的时候加以注意。但是没有提供一种验证方式,这些类是否正确实现了这些接口中的方法,这种方式就是一种文档化的作法。
2. 属性验证(Emulating Interfaces with Attribute Checking)
例子:
复制代码 代码如下:
/* interface
Composite {
function add(child);
function remove(child);
function getChild(index);
}
interface FormItem {
function save();
}
*/
var CompositeForm = function(id, method, action) {
this.implementsInterfaces = ['Composite', 'FormItem'];
...
};
...
function addForm(formInstance) {
if(!implements(formInstance, 'Composite', 'FormItem')) {
throw new Error("Object does not implement a required interface.");
}
...
}
// The implements function, which checks to see if an object declares that it
// implements the required interfaces.
function implements(object) {
for(var i = 1; i arguments.length; i++) {
// Looping through all arguments
// after the first one.
var interfaceName = arguments[i];
var interfaceFound = false;
for(var j = 0; j object.implementsInterfaces.length; j++) {
if(object.implementsInterfaces[j] == interfaceName) {
interfaceFound = true;
break;
}
}
if(!interfaceFound) {
return false;
// An interface was not found.
}
}
return true;
// All interfaces were found.
}
这种方式比第一种方式有所改进,接口的定义仍然以注释的方式实现,但是添加了验证方法,判断一个类型是否实现了某个接口。
3.鸭子类型(Emulating Interfaces with Duck Typing)
复制代码 代码如下:
// Interfaces.
var Composite = new Interface('Composite', ['add', 'remove', 'getChild']);
var FormItem = new Interface('FormItem', ['save']);
// CompositeForm class
var CompositeForm = function(id, method, action) {
...
};
...
function addForm(formInstance) {
ensureImplements(formInstance, Composite, FormItem);
// This function will throw an error if a required method is not implemented.
...
}
// Constructor.
var Interface = function(name, methods) {
if(arguments.length != 2) {
throw new Error("Interface constructor called with "
+ arguments.length + "arguments, but expected exactly 2.");
}
this.name = name;
this.methods = [];
for(var i = 0, len = methods.length; i len; i++) {
if(typeof methods[i] !== 'string') {
throw new Error("Interface constructor expects method names to be "
+ "passed in as a string.");
}
this.methods.push(methods[i]);
}
};
// Static class method.
Interface.ensureImplements = function(object) {
if(arguments.length 2) {
throw new Error("Function Interface.ensureImplements called with "
+arguments.length + "arguments, but expected at least 2.");
}
for(var i = 1, len = arguments.length; i len; i++) {
var interface = arguments[i];
if(interface.constructor !== Interface) {
throw new Error("Function Interface.ensureImplements expects arguments"
+ "two and above to be instances of Interface.");
}
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("Function Interface.ensureImplements: object "
+ "does not implement the " + interface.name + " interface. Method " + method + " was not found.");
}
}
}
};
何时使用接口?
一直使用严格的类型验证并不适合,因为大多数javascript程序员已经在没有接口和接口验证的情况下编程多年。当你用设计模式开始设计一个很复杂的系统的时候,使用接口更有益处。看起来使用接口好像限制了javascript的灵活性,但实际上他让你的代码变得更加的松耦合。他使你的代码变得更加灵活,你可以传送任何类型的变量,并且保证他有你想要的方法。有很多场景接口非常适合使用。
在一个大型系统里,很多程序员一起参与开发项目,接口就变得非常必要了。程序员经常要访问一个还没有实现的api,或者为其他程序员提供别人依赖的一个方法存根,在这种情况下,接口变得相当的有价值。他们可以文档化api,并作为编程的契约。当存根被实现的api替换的时候你能立即知道,如果在开发过程中api有所变动,他能被另一个实现该接口的方法无缝替换。
如何使用接口?
首先要解决的问题是,在你的代码中是否适合使用接口。如果是小项目,使用接口会增加代码的复杂度。所以你要确定使用接口的情况下,是否是益处大于弊端。如果要使用接口,下面有几条建议:
1.引用Interface 类到你的页面文件。interface的源文件你可以再如下站点找到: .
2.检查你的代码,确定哪些方法需要抽象到接口里面。
3.创建接口对象,没个接口对象里面包含一组相关的方法。
4.移除所有构造器验证,我们将使用第三种接口实现方式,也就是鸭子类型。
5.用Interface.ensureImplements替代构造器验证。
您可能感兴趣的文章:
小议javascript 设计模式 推荐
JavaScript 设计模式之组合模式解析
javascript 设计模式之单体模式 面向对象学习基础
JavaScript 设计模式 安全沙箱模式
JavaScript设计模式之观察者模式(发布者-订阅者模式)
JavaScript设计模式之原型模式(Object.create与prototype)介绍
JavaScript设计模式之工厂方法模式介绍
javascript设计模式之中介者模式Mediator
学习JavaScript设计模式之责任链模式
当前标题:javascript解耦,解耦的定义
文章来源:http://pwwzsj.com/article/dsgsjsc.html