在学习设计模式前必须要知道和掌握的***。

  为类添加新方法:

  1. Function.prototype.method = function(name,fn) {
  2. this.prototype[name] = fn;
  3. }
  4.  
  5. //改进版:支持链式调用
  6.  
  7. Function.prototype.method = function(name,fn) {
  8. this.prototype[name] = fn;
  9. return this;
  10. }

  函数是一等对象,可以存储在变量中,可以作为参数传给其他函数,可以作为返回值从其他函数传出,还可以再运行的时候进行构造。这正是用以构造传统面向对象框架的基础。

  对象具有易变性。类方法可以在类实例创建之后再添加,实例仍然能够获得新添加的方法。个人觉得,这也是对象扩展的威力源泉。

  一、接口

  “针对接口,而不是实现编程”

  接口提供了一种用以说明一个对象应该具备哪些方法的手段。既定的一批接口具有自我描述性,并能促进代码的重用。接口可以告诉程序员一个类实现了哪些方法,从而帮助其使用这个类。接口最实在的用途是什么?~一个程序员可以针对所需要的类定义一个接口,并转交给另一个程序员。第二个程序员可以随心所欲地编写自己的代码,只要他定义的类实现了那个接口就行。

  当然接口也有弊端。比如额外的方法调用的开销无法避免。

  而接口使用中的最大问题在于,无法强迫其他程序员遵守你定义的接口。不像其它语言(像java等,编译期间会因为接口继承后没有写实现而报错),javascript中必须用手工的办法保证某个类实现了一个接口(你可能对此不理解是什么意思,稍安,等下立马解释^_^)。如果项目的其他程序员不认真对待接口,那么这些接口的使用是无法得到强制性保证的。除非项目的所有人都同意使用接口并对其进行检查,否则接口的很多价值都无从体现。

  解惑的时候到了,为什么前文说“javascript中必须用手工的办法保证某个类实现了一个接口”。事实上,javascript没有interface和implements关键字,也不在运行时对接口约定是否得到遵守进行检查。我们只能在javascript中模仿接口。一下介绍模仿接口的三种方法:注释法、属性检查法、鸭式辨型法。

  ① 注释法:

  1. /*
  2. interface Composite {
  3. function add(child);
  4. function remove(child);
  5. function getChild(index);
  6. }
  7.  
  8. interface FormItem {
  9. function sava();
  10. }
  11. */
  12.  
  13. var compositeForm = function (id,method,action) {
  14. ....
  15. };
  16.  
  17. compositeForm.prototype.add = function(child) {
  18. ....
  19. };
  20.  
  21. compositeForm.prototype.remove = function(child) {
  22. .....
  23. };

  这种方法易于实现,但是不会提供错误信息。

  ② 用属性检查模仿接口

  1. /*
  2. interface Composite {
  3. function add(child);
  4. function remove(child);
  5. function getChild(index);
  6. }
  7.  
  8. interface FormItem {
  9. function sava();
  10. }
  11. */
  12.  
  13. var compositeForm = function(id,method,action) {
  14. this.implementInterfaces = ['Composite','FormItem'];
  15. ......
  16. };
  17.  
  18. function addForm(formInstance) {
  19. if(!implements(formInstance,'Composite','FormItem')) {
  20. throw new Error("Object does not implement a required interface.");
  21. ....
  22. }
  23. }
  24.  
  25. function implement(object) { //检查接口是否被实现
  26. for(var i = 0;i < arguments.length;i++) {
  27. var interfaceName = arguments[i];
  28. var interfaceFound = false;
  29. for(var j = 0;j < object.implementsInterfaces.length;j++) {
  30. if(interfaceName == object.implementsInterfaces[j]) {
  31. interfaceFound = true;
  32. break;
  33. }
  34. }
  35. if(!interfaceFound) {
  36. return false;
  37. }
  38. }
  39. return true;
  40. }

  优点:它对所有实现的接口提供了文档说明。如果需要的接口不在一个类宣称支持的接口之列,你会看到错误消息。通过利用这些错误,你可以强迫其它程序员声明这些接口。

  缺点:它并未确保类真正实现自称实现的接口。很可能,只是有了这个接口的实现声明,方法体忘记写了,一个空的方法体造成了假象。

  ③ 用鸭式辨型模仿接口

  思想:类是否声明自己支持哪些接口不重要,只要它具有这些接口中的方法就行。“像鸭子一样走路并且嘎嘎叫的就是鸭子”。如果一个对象具有与接口定义的方法同名的所有方法,那么就可以认为它实现了这个接口。(个人觉得,这有点像客户端检测机制,我们不是去判断浏览器的类型,而是转而判断浏览器是否支持此项功能^_^换个角度思考问题往往有事半功倍之效。)

  缺点:类并不声明自己实现了哪些接口,这降低了代码的可重用性,并且也缺乏其他两种方法的自我描述性。

  

  个人觉得,最好的就接口实现时方法一和方法三的结合。也就是可读性和保证性相结合。

  1. var Composite = new Interface('Composite',['add','remove','getChild']);
  2. var FormItem = new Interface('FormItem',['save']);
  3.  
  4. var CompositeForm = function(id,method,action) {
  5. ....
  6. };
  7.  
  8. function addForm(formInstance) {
  9. Interface.ensureImplements(formInstance,Composite,FormItem);
  10. ....
  11. }
  12.  
  13. var Interface = function(name,methods) {
  14. if(arguments.length != 2) {
  15. throw new Error("...........");
  16. }
  17.  
  18. this.name = name;
  19. this.methods = [];
  20. for(var i = 0;i < methods.length;i++) {
  21. if(typeof methods[i] !== 'string') {
  22. throw new Error("..........");
  23. }
  24. this.methods.push(methods[i]);
  25. }
  26. };
  27.  
  28. Interface.ensureImplements = function() {
  29. if(arguments.length < 2) {
  30. throw new Error("....");
  31. }
  32.  
  33. for(var i = 1,len = arguments.length;i < len;i++) {
  34. var interface = arguments[i];
  35. if(interface.constructor !== Interface) {
  36. throw new Error("....");
  37. }
  38.  
  39. for(var j = 0,methodsLen = interface.methods.length;j < methodsLen;j++) {
  40. var method = interface.methods[j];
  41. if(!object[method]||typeof object[method] !== 'function') {
  42. throw new Error("....");
  43. }
  44. }
  45. }
  46. }

  接口在运用设计模式实现复杂系统的时候最能体现其价值。降低了对象间的耦合程度。在大型项目中,易于程序员的合作,如果你知道测试中的桩测试,你对此用个空方法体进行占位,提供API,无疑会使程序员间的合作开发更便捷。

  

深入js的面向对象学习篇——温故知新(一)的更多相关文章

  1. 深入js的面向对象学习篇(继承篇)——温故知新(三)

    写这篇有关继承的文章时,突然想起,几天前的面试.因为习惯在学习知识的时候加上自己的理解,很喜欢用自己话来解释,于是乎当面试被问起继承原理时,噼里啪啦一大堆都是自己组织的话,(也可能是因为个人紧张.外加 ...

  2. 深入js的面向对象学习篇(封装是一门技术和艺术)——温故知新(二)

    下面全面介绍封装和信息隐藏. 通过将一个方法或属性声明为私用的,可以让对象的实现细节对其它对象保密以降低对象之间的耦合程度,可以保持数据的完整性并对其修改方式加以约束.在代码有许多人参与设计的情况下, ...

  3. 【js】面向对象学习资料

    1.面向对象模式: https://m.jb51.net/article/74549.htm 2.面向对象基础篇 http://www.cnblogs.com/chiangchou/p/js-oop1 ...

  4. js之面向对象----封装篇

    学习了一天的面向对象总结一下,共分为三类 - -! 老规矩 第一部分是概念性知识!!! 面向对象编程,我们可以把他想象成我们在造人.一个对象便是一个人,这个人有胳膊有腿,这便是一个对象的属性或者方法. ...

  5. js面向对象学习 - 对象概念及创建对象

    原文地址:js面向对象学习笔记 一.对象概念 对象是什么?对象是“无序属性的集合,其属性可以包括基本值,对象或者函数”.也就是一组名值对的无序集合. 对象的特性(不可直接访问),也就是属性包含两种,数 ...

  6. js学习篇1--数组

    javascript的数组可以包含各种类型的数据. 1. 数组的长度 ,直接用 length 属性; var arr=[1,2,3]; arr.length; js中,直接给数组的length赋值是会 ...

  7. js面向对象学习

    纯属笔记,加强记忆,不是教程,欢迎纠错,没有逻辑,不太适合学习使用. -------------- 继承多态等太多概念难以理解,还是从实践中慢慢学吧!争取能大致看懂网上的开源的代码. -------- ...

  8. 我的JS 中级学习篇

    在codefordream上进入中级学习后,感觉立马从js的基础学习往前跳了好远,上面的东西好像都是第一次看到一样.这时候才发现,说来也曾接触过js,但是这时候才发现对js的认识就停在知道两点:js中 ...

  9. JavaScript--我发现,原来你是这样的JS:面向对象编程OOP[2]--(创建你的那个对象吧)

    一.介绍 我们继续面向对象吧,这次是面向对象编程的第二篇,主要是讲创建对象的模式,希望大家能从博客中学到东西. 时间过得很快,还是不断的学习吧,为了自己的目标. 二.创建对象 1.前面的创建对象方式 ...

随机推荐

  1. 【Cocos2d入门教程六】Cocos2d-x事件篇之触摸

    Cocos游戏当中产生一个事件时,可以有多个对象在监听该事件,所以有优先级(Priority).优先级越高(Priority值越小),事件响应越靠前. 关系图: 新 事件分发机制:在2.x 版本事件处 ...

  2. Ajax-数据格式-html

  3. lstm-思想2

    LSTM 网络 Long Short Term 网络—— 一般就叫做 LSTM ——是一种 RNN 特殊的类型,可以学习长期依赖信息.LSTM 由 Hochreiter & Schmidhub ...

  4. Setup Project 安装项目

    从vs2012起,微软已经不支持setup project了.以此纪念一下setup project.   在新建Setup Project   增加安装内容,通常是直接Oupput一个项目,或者直接 ...

  5. STL Traits编程技法

    traits编程技法大量运用于STL实现中.通过它在一定程度上弥补了C++不是强型别语言的遗憾,增强了C++关于型别认证方面的能力. traits编程技法是利用“内嵌型别”的编程技法和编译器的temp ...

  6. 如何在IOS开发中在自己的framework中添加.bunble文件

    今天就跟大家介绍一下有关,如何在IOS开发中在自己的framework中添加.bunble文件,该文章我已经在IOS教程网(http://ios.662p.com)发布过来,个人觉得还是对大家有帮助的 ...

  7. 快速解码base64和utf-8的ASCII编码和URL解码

    看论坛上总是有人发乱七八糟的文字,根本看不懂,用下面的方法解密一下. 只要有浏览器的开发者工具就行了. UTF-16解码 console.log("\u5475\u5475") U ...

  8. 【转】winform带参数启动另一个exe

     启动EXE string arg1 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; string arg2 = "bbbbbbbbbbbbbbbb ...

  9. c#中const与readonly区别

    const 的概念就是一个包含不能修改的值的变量.常数表达式是在编译时可被完全计算的表达式.因此不能从一个变量中提取的值来初始化常量.如果 const int a = b+1;b是一个变量,显然不能再 ...

  10. Spring Cloud OAuth

    In this blog post we will create a secure API for external access, using OAuth 2.0, to the microserv ...