首页 web前端 js教程 Javascript aop(面向切面编程)之around(环绕)分析_javascript技巧

Javascript aop(面向切面编程)之around(环绕)分析_javascript技巧

May 16, 2016 pm 04:01 PM
aop javascript

Aop又叫面向切面编程,其中“通知”是切面的具体实现,分为before(前置通知)、after(后置通知)、around(环绕通知),用过spring的同学肯定对它非常熟悉,而在js中,AOP是一个被严重忽视的技术点。但是利用aop可以有效的改善js代码逻辑,比如前端框架dojo和yui3中AOP则被提升至自定义事件的一种内在机制,在源码中随处可见。得益于这种抽象使得dojo的自定义事件异常强大和灵活。dojo中aop的实现在dojo/aspect模块中,主要有三个方法:before、after、around,本文会带领大家一步步实现around方法,后续文章将会深入解析dojo/aspect模块的结构体系。

js要实现环绕通知,最简单也最应被想到的就是利用callback(回调)

1

2

3

4

5

6

7

8

9

10

11

advice = function(originalFunc){

 console.log("before function");

 originalFunc();

 console.log("after function");

}

var obj = {

 foo: function(){

 console.log('foo');

 }

}

advice(obj.foo)

登录后复制

结果:

before function
foo
after function  
哈哈,太简单了,是不是可以回去睡觉了。。。。  

可是,是不是有点太粗糙了。。。。说好的环绕呢。。。。至少下次调用obj.foo也应该是这个结果,而不是一个干巴巴的“foo”;为此我我们需要在改动一下,利用一下闭包

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

advice = function(originalFunc){

 return function() {

 console.log("before function");

 originalFunc();

 console.log("after function");

 }

}

var obj = {

 foo: function(){

 console.log(this.name);

 },

 name: "obj"

}

obj.foo = advice(obj.foo)

obj.foo()

登录后复制

 输出:

before function

after function

看起来达到了环绕的效果,but说好的name哪去了。。。。

在advice返回的闭包中我们还要处理作用域问题

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

advice = function(originalFunc){

 return function() {

 console.log("before function");

 originalFunc();

 console.log("after function");

 }

}

var obj = {

 foo: function(){

 console.log(this.name);

 },

 name: "obj"

}

 

keepContext = function() {

 return obj['foo'].call(obj);

}

 

obj.foo = advice(keepContext);

登录后复制

看起来是利用call解决了作用域问题,我们运行一下看看:

卧槽,难道这就是传说中的死循环。。。。

  看来还是得改变一下,借助一个中间变量消除死循环

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

advice = function(originalFunc){

 return function() {

 console.log("before function");

 originalFunc();

 console.log("after function");

 }

}

var obj = {

 foo: function(){

 console.log(this.name);

 },

 name: "obj"

}

 

var exist = obj.foo;

 

keepContext = function() {

 return exist.call(obj);

}

 

obj.foo = advice(keepContext);

obj.foo();

登录后复制

输出:

before function
obj
after function  

哈哈,世界突然变得美好了。。。。
但是这一堆代码看起来是不是太low了,我们是不是要来点高大上的抽象,嗯,我也是这么想的

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

function around(obj, prop, advice){

 var exist = obj[prop];

 var advised = advice(function(){

 return exist.call(obj, arguments);

 });

 obj[prop] = advised;

}

 

advice = function(originalFunc){

 return function() {

 console.log("before function");

 originalFunc();

 console.log("after function");

 }

}

var obj = {

 foo: function(){

 console.log(this.name);

 },

 name: "obj"

}

 

around(obj, 'foo', advice);

 

obj.foo();

登录后复制

around方法将处理过程与具体对象解耦;advice只要按照如下格式来书写,就可以达到around的效果

1

2

3

4

5

6

7

advice = function(originalFunc){

 return function() {

 //before

 originalFunc();

 //after

 }

}

登录后复制

哈哈,瞬间高大上,狂拽酷炫掉渣天,有木有。。。。

  

  那么问题来了:如果不小心多调用了一次around方法肿么办。。。。 额。。。。这是个问题 我们是不是应该让around返回一个句柄,里面有个remove方法,消除绑定,就像绑定/移除事件一样。

  所为remove,就是让函数下次执行时不在执行对应的around方法,而仅仅运行originalFunc方法

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

function around(obj, prop, advice){

 var exist = obj[prop];

 var previous = function(){

 return exist.call(obj, arguments);

 };

 var advised = advice(previous);

 obj[prop] = advised;

  

 return {

 remove: function(){

 obj[prop] = exist;

 advice = null;

 previous = null;

 exist = null;

 obj = null;

 }

 }

}

var count = 1;

advice = function(originalFunc){

 var current = count++;

 return function() {

 console.log("before function " + current);

 originalFunc(arguments);

 console.log("after function " + current);

 }

}

var obj = {

 foo: function(arg){

 console.log(this.name + " and " + arg);

 },

 name: "obj"

}

 

h1 = around(obj, 'foo', advice);

h2 = around(obj, 'foo', advice);

obj.foo();

h1.remove();

obj.foo();

h2.remove();

obj.foo();

登录后复制

输出:

1

2

3

4

5

6

7

before function 2

before function 1

obj and [object Arguments]

after function 1

after function 2

obj and undefined

before function 1

登录后复制

这个。。不但结果有点乱。。。还报错了。。。。是可忍,叔不可忍,叔可忍,嫂不可忍!

  啊,闭包。。。请赐予我力量吧!

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

function around(obj, prop, advice){

 var exist = obj[prop];

 var previous = function(){

 return exist.apply(obj, arguments);

 };

 var advised = advice(previous);

 obj[prop] = function(){

 //当调用remove后,advised为空

 //利用闭包的作用域链中可以访问到advised跟previous变量,根据advised是否为空可以来决定调用谁

 return advised ? advised.apply(obj, arguments) : previous.apply(obj, arguments);

 };

  

 return {

 remove: function(){

 //利用闭包的作用域链,在remove时将advised置空,这样执行过程中不会进入本次around

 //这几个不能删

 //obj[prop] = exist;

 advised = null;

 advice = null;

 //previous = null;

 //exist = null;

 //obj = null;

 }

 }

}

var count = 1;

advice = function(originalFunc){

 var current = count++;

 return function() {

 console.log("before function " + current);

 originalFunc.apply(this, arguments);

 console.log("after function " + current);

 }

}

var obj = {

 foo: function(arg){

 console.log(this.name + " and " + arg);

 },

 name: "obj"

}

 

h1 = around(obj, 'foo', advice);

h2 = around(obj, 'foo', advice);

obj.foo('hello world');

h1.remove();

obj.foo('hello world');

h2.remove();

obj.foo('hello world');

登录后复制

输出:

1

2

3

4

5

6

7

8

9

before function 2

before function 1

obj and hello world

after function 1

after function 2

before function 2

obj and hello world

after function 2

obj and hello world

登录后复制

打完,收功!

  第一次通宵写博客也是醉了,两点钟听到隔壁fuck me,四点钟听到乌鸦啼鸣,还有一种不知道什么鸟,啾啾的叫,五点钟这个时候一堆鸟叫。。。。

参考文章:

使用AOP改善javascript代码

yui3的AOP(面向切面编程)和OOP(面向对象编程)

面向切面编程(AOP)的理解

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

如何使用WebSocket和JavaScript实现在线语音识别系统 如何使用WebSocket和JavaScript实现在线语音识别系统 Dec 17, 2023 pm 02:54 PM

如何使用WebSocket和JavaScript实现在线语音识别系统引言:随着科技的不断发展,语音识别技术已经成为了人工智能领域的重要组成部分。而基于WebSocket和JavaScript实现的在线语音识别系统,具备了低延迟、实时性和跨平台的特点,成为了一种被广泛应用的解决方案。本文将介绍如何使用WebSocket和JavaScript来实现在线语音识别系

WebSocket与JavaScript:实现实时监控系统的关键技术 WebSocket与JavaScript:实现实时监控系统的关键技术 Dec 17, 2023 pm 05:30 PM

WebSocket与JavaScript:实现实时监控系统的关键技术引言:随着互联网技术的快速发展,实时监控系统在各个领域中得到了广泛的应用。而实现实时监控的关键技术之一就是WebSocket与JavaScript的结合使用。本文将介绍WebSocket与JavaScript在实时监控系统中的应用,并给出代码示例,详细解释其实现原理。一、WebSocket技

如何利用JavaScript和WebSocket实现实时在线点餐系统 如何利用JavaScript和WebSocket实现实时在线点餐系统 Dec 17, 2023 pm 12:09 PM

如何利用JavaScript和WebSocket实现实时在线点餐系统介绍:随着互联网的普及和技术的进步,越来越多的餐厅开始提供在线点餐服务。为了实现实时在线点餐系统,我们可以利用JavaScript和WebSocket技术。WebSocket是一种基于TCP协议的全双工通信协议,可以实现客户端与服务器的实时双向通信。在实时在线点餐系统中,当用户选择菜品并下单

如何使用WebSocket和JavaScript实现在线预约系统 如何使用WebSocket和JavaScript实现在线预约系统 Dec 17, 2023 am 09:39 AM

如何使用WebSocket和JavaScript实现在线预约系统在当今数字化的时代,越来越多的业务和服务都需要提供在线预约功能。而实现一个高效、实时的在线预约系统是至关重要的。本文将介绍如何使用WebSocket和JavaScript来实现一个在线预约系统,并提供具体的代码示例。一、什么是WebSocketWebSocket是一种在单个TCP连接上进行全双工

JavaScript和WebSocket:打造高效的实时天气预报系统 JavaScript和WebSocket:打造高效的实时天气预报系统 Dec 17, 2023 pm 05:13 PM

JavaScript和WebSocket:打造高效的实时天气预报系统引言:如今,天气预报的准确性对于日常生活以及决策制定具有重要意义。随着技术的发展,我们可以通过实时获取天气数据来提供更准确可靠的天气预报。在本文中,我们将学习如何使用JavaScript和WebSocket技术,来构建一个高效的实时天气预报系统。本文将通过具体的代码示例来展示实现的过程。We

简易JavaScript教程:获取HTTP状态码的方法 简易JavaScript教程:获取HTTP状态码的方法 Jan 05, 2024 pm 06:08 PM

JavaScript教程:如何获取HTTP状态码,需要具体代码示例前言:在Web开发中,经常会涉及到与服务器进行数据交互的场景。在与服务器进行通信时,我们经常需要获取返回的HTTP状态码来判断操作是否成功,根据不同的状态码来进行相应的处理。本篇文章将教你如何使用JavaScript获取HTTP状态码,并提供一些实用的代码示例。使用XMLHttpRequest

javascript中如何使用insertBefore javascript中如何使用insertBefore Nov 24, 2023 am 11:56 AM

用法:在JavaScript中,insertBefore()方法用于在DOM树中插入一个新的节点。这个方法需要两个参数:要插入的新节点和参考节点(即新节点将要被插入的位置的节点)。

JavaScript和WebSocket:打造高效的实时图像处理系统 JavaScript和WebSocket:打造高效的实时图像处理系统 Dec 17, 2023 am 08:41 AM

JavaScript是一种广泛应用于Web开发的编程语言,而WebSocket则是一种用于实时通信的网络协议。结合二者的强大功能,我们可以打造一个高效的实时图像处理系统。本文将介绍如何利用JavaScript和WebSocket来实现这个系统,并提供具体的代码示例。首先,我们需要明确实时图像处理系统的需求和目标。假设我们有一个摄像头设备,可以采集实时的图像数

See all articles