《JavaScript设计模式》笔记之第一、二章



第一章

创建一个类

方法一:

var Anim = function() {

...

};

Anim.prototype.start = function() {

...

};

Anim.prototype.stop = function() {

...

};

方法二:

var Anim = function() {

...

};

Anim.prototype = {

start: function() {

...

},

stop: function() {

...

}

};

方法三:

Function.prototype.method =  function(name, fn) {

this.prototype[name] = fn;

};

var Anim = function() {

...

};

Anim.method(‘start‘, function() {

...

});

Anim.method(‘stop‘, function() {

...

});

方法四(在方法三上增加链式调用):

只需要在method方法上添加return this;

Function.prototype.method =  function(name, fn) {

this.prototype[name] = fn;

return this;

};


第二章

接口模仿

方法一:用注释描述接口

/*

interface Composite {

function add(child);

function remove(child);

}

*/

var CompositeForm = function(id, method, action) { //inplements Composite

...

};

//继承Composite接口

CompositeForm.prototype.add = function(child) {

...

};

CompositeForm.prototype.remove = function(child) {

...

};

缺点:主要利用注释来口头约束,要靠程序员自觉遵守

优点:不需要额外的类或函数,简单方便


方法二:用属性检查模仿接口

说明:在方法一中增加代码,主要是在需要继承某些接口的类中添加一个属性用于,告诉别人它有没有继承某些类,此外,再增加一个检查执行的函数,就可以方便的检查某个类是否继承了某些接口

缺点: 如果程序员只是声明了自己有实现那个接口,但是没有实际实现,就会造成问题

优点: 如果程序员正真按照约定,没在代码上说谎,那么就能有效的检测是否实现了接口

例子:

/*

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 implements(object) {

for(var i=1; i<arguments.length; i++) {

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;

}

return true;

}

// 使用例子

function addForm(formInstance) {

if(!implements(formInstance, ‘Composite‘, ‘FormItem‘)) {

throw new Error("没有实现某些接口");

}

...

}


方法三:鸭式辩型模仿接口

例子:

// 接口列表(个人理解:使用neInterface只是让别人知道这是一个接口定义,简单点可以直接用一个数组来代替)

var Composite = new Interface(‘Composite‘, [‘add‘, ‘remove‘, ‘getChild‘]);

var FormItem = new Interface(‘FormItem‘, [‘save‘]);

//使用的时候通过一个定义好的函数ensureImplements来检查是否实现了接口

ensureImplements(formInstance, Composite, FormItem);

说明: 这种方法的思想就是检测对象是否有与接口同名的方法


方法四:结合方法一和方法三的方法

例子:

// 接口列表

var Composite = new Interface(‘Composite‘, [‘add‘, ‘remove‘, ‘getChild‘]);

var FormItem = new Interface(‘FormItem‘, [‘save‘]);

// 要实现上述接口的类

var CompositeForm = function(id, method, action) {

... // 实现Composit接口和FormItem接口

};

function addForm(formInstance) {

Interface.ensureImplements(formInstance, Composite, FormItem);

}


Interface 类

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]);

}

};

// 验证实现的方法


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

Interface.ensureImplements = function(object) {

    if(arguments.length < 2) {

        throw new Error("Interface.ensureImplements函数接收到的参数个数:"+arguments.length+",但是函数需要的参数个数为:2");

    }

    for(var i = 1, len = arguments.length; i < len; i++) {

        var interface = arguments[i];

        if(interface.constructor !== Interface) {

            throw new Error("Interface.ensureImplements函数需要参数2以及后面的参数为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("Interface.ensureImplements函数: 实例没有实现以下方法:"+interface.name);

            }

        }

    }

};


综合例子:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

<html>

<body>

    <script>

        //Interface 类

        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]);

            }

        };

        Interface.ensureImplements = function (object) {

            if (arguments.length < 2) {

                throw new Error("Interface.ensureImplements函数接收到的参数个数:" + arguments.length + ",但是函数需要的参数个数为:2");

            }

            for (var i = 1, len = arguments.length; i < len; i++) {

                var interface = arguments[i];

                if (interface.constructor !== Interface) {

                    throw new Error("Interface.ensureImplements函数需要参数2以及后面的参数为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("Interface.ensureImplements函数: 实例没有实现以下方法:" + interface.name);

                    }

                }

            }

        };

        

        //定义了一个接口,接口需要有run方法和jump方法

        var Animal = new Interface(‘Animal‘,[‘run‘‘jump‘]);

        

        //实现Animal接口的Cat类

        function Cat() {}

        Cat.prototype.run = function() {};

        Cat.prototype.jump = function() {};

        

        //实现Animal接口的Dog类

        function Dog() {}

        Dog.prototype.run = function() {};

        Dog.prototype.jump = function() {};

        

        //没有实现Animal的Car类

        function Car() {}

        Car.prototype.drive = function() {};

        

        //有一只猫叫cat,有一只狗叫dog,有一部车叫car

        var cat = new Cat();

        var dog = new Dog();

        var car = new Car();

        

        //假设一个人叫啊Mark,然后他很喜欢收养动物,今天他又来收养动物了。

        var Mark = {

            adopt: function(animal) {

                Interface.ensureImplements(animal, Animal);

                console.log("收养一只"+animal.constructor.name+"成功");

            }

        };

        Mark.adopt(cat);

        Mark.adopt(dog);

        Mark.adopt(car);

        

    </script>

</body>

</html>

时间: 2024-12-09 09:56:58

《JavaScript设计模式》笔记之第一、二章的相关文章

Android群英传笔记——第十二章:Android5.X 新特性详解,Material Design UI的新体验

Android群英传笔记--第十二章:Android5.X 新特性详解,Material Design UI的新体验 第十一章为什么不写,因为我很早之前就已经写过了,有需要的可以去看 Android高效率编码-第三方SDK详解系列(二)--Bmob后端云开发,实现登录注册,更改资料,修改密码,邮箱验证,上传,下载,推送消息,缩略图加载等功能 这一章很多,但是很有趣,也是这书的最后一章知识点了,我现在还在考虑要不要写这个拼图和2048的案例,在此之前,我们先来玩玩Android5.X的新特性吧!

Java学习笔记—第十二章 Java网络编程入门

第十二章  Java网络编程入门 Java提供的三大类网络功能: (1)URL和URLConnection:三大类中最高级的一种,通过URL网络资源表达方式,可以很容易确定网络上数据的位置.利用URL的表示和建立,Java程序可以直接读入网络上所放的数据,或把自己的数据传送到网络的另一端. (2)Socket:又称"套接字",用于描述IP地址和端口(在Internet中,网络中的每台主机都有一个唯一的IP地址,而每台主机又通过提供多个不同端口来提供多种服务).在客户/服务器网络中,当客

[CSAPP笔记][第十二章并发编程]

第十二章 并发编程 如果逻辑控制流在时间上是重叠,那么它们就是并发的(concurrent).这种常见的现象称为并发(concurrency). 硬件异常处理程序,进程和Unix信号处理程序都是大家熟悉的例子. 我们主要将并发看做是一种操作系统内核用来运行多个应用程序的机制. 但是,并发不仅仅局限于内核.它也可以在应用程序中扮演重要的角色. 例如 Unix信号处理程序如何允许应用响应异步事件 例如:用户键入ctrl-c 程序访问虚拟存储器的一个未定义的区域 其他情况 访问慢速I/O设备 当一个应

Linux第一二章笔记

第一章 Linux内核简介 1. Unix内核的特点 简洁:仅提供系统调用并有一个非常明确的设计目的 抽象:几乎所有东西都被当做文件 可移植性:使用C语言编写,使得其在各种硬件体系架构面前都具备令人惊异的移植能力 进程:创建迅速,一次执行保质保量地完成一个任务:独特的fork系统调用 清晰的层次化结构:策略和机制分离的理念,简单的进程间通信元语把单一目的的程序方便地组合在一起 2. 关于Linux内核简介 Linux是基于Unix的类Unix系统,设计思想相似,比如它也实现了Unix的API.但

《Linux内核设计与实现》第一二章笔记

第一章 linux内核简介 每个处理器在任何时间点上的活动必然概括为下列三者: 运行于用户空间,执行用户进程 运行于内核空间,处于进程上下文,代表某个特定的进程执行 运行于内核空间,处于中断上下文,与任何进程无关,处理某个特定的中断 Linux内核与传统的Unix系统之间的差异: linux内核可以抢占 linux内核并不区分线程和其他一般进程 linux提供具有设备类的面向对象的设备模型.热插拔事件,以及用户空间的设备文件系统 linx忽略了一些被认为设计得很拙劣的unix特性,及难以实现的过

linux内核设计与实现一书阅读整理 之第一二章整合

第一章:Linux内核简介 一.Unix和linux Unix是一个强大.健壮和稳定的操作系统. 1.Unix内核特点 十分简洁:仅提供几百个系统调用并且有明确的目的: 在Unix中,大部分东西都被(或者正致力于)被当做文件对待: Unix内核即相关系统工具软件都是用C语言编写的,这使得系统有着强大的可移植性: Unix进程创建非常迅速,目标在于一次执行保质保量地完成一个任务 2.Linux与Unix异同 Linux是基于Unix的类系统,比如它也实现了Unix的API: 但它不同于Unix,没

JavaScript 学习笔记— —闭包(二)

闭包有三个特性: 1.函数嵌套函数 2.函数内部可以引用外部的参数和变量 3.参数和变量不会被垃圾回收机制回收 闭包的定义及其优缺点 闭包 是指有权访问另一个函数作用域中的变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量 使用闭包有一个优点,也是它的缺点,就是可以把局部变量驻留在内存中,可以避免使用全局变量.全局变量在每个模块都可调用,这势必将是灾难性的.(所以推荐使用私有的,封装的局部变量.) 一般函数执行完毕后,局部活动对象就被销毁,内存

《APUE》读书笔记第十二章-线程控制

本章中,主要是介绍控制线程行为方面的内容,同时介绍了在同一进程中的多个线程之间如何保持数据的私有性以及基于进程的系统调用如何与线程进行交互. 一.线程属性 我们在创建线程的时候可以通过修改pthread_attr_t结构的值来修改线程的属性,将这些属性与创建的线程联系起来.调用pthread_attr_init以后,pthread_attr_t结构所包含的内容就是操作系统实现支持的线程所有属性. #include <pthread.h> int pthread_attr_init(pthrea

Linux 笔记 - 第十二章 Shell 脚本

博客地址:http://www.moonxy.com 一.前言 常见的编程语言分为两类:一类是编译型语言,如:C.C++ 和 Java等,它们远行前要经过编译器的编译.另一类是解释型语言,不需要编译,执行时,需要使用解释器一行一行地解释执行,如:awk.perl.python 和 shell 等. Shell 是一种脚本语言,属于上面提到的第二类语言,就必须有对应的解释器来执行这些脚本,最常见的脚本解释器是:bash. 在编写 Shell 脚本时,我们不仅会用到很多的 Linux 命令.正则表达

《JAVA编程思想》学习笔记——第十二章 通过异常处理错误

Java的基本理念是 "结构不佳的代码不能运行" 发现错误的理想时机是在编译阶段,也就是在你试图运行程序之前.然而,编译期间并不能找出所有的错误,余下的问题必须在运行期间解决.这就需要错误源能通过某种方式,把适当的信息传递给某个接收者----该接收者将知道如何正确处理这个问题. 异常情形是指阻止当前方法或作用域继续执行的问题. 当抛出异常后,有几件事会随之发生.首先,同Java中其它对象的创建一样,将使用new在堆上创建异常对象.然后,当前的执行路径被终止,并且从当前环境中弹出对异常对