1、通用方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| Function.prototype.before = function( beforefn ) { const _self = this; return () => { beforefn.apply( this, arguments ) return _self.apply( this, arguments ) } }
Function.prototype.after = function( afterfn ) { const _self = this; return () => { const ret = _self.apply( this, arguments ) afterfn.apply( this, arguments ) return ret } }
|
不污染写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const before = function ( fn, beforefn ) { return function(){ beforefn.apply( this, arguments ) return fn.apply( this, arguments ) } }
const a = before( function(){alert(3)}, function(){alert(2)} )
a = before(a, function(){alert(1)}) a()
|
2、例子:数据统计上报
1 2 3 4 5 6 7 8 9 10 11
| const showLogin = () => { console.log( '打开登录浮层' ) }
const log = () => { console.log( `上报标签为:${this.getAttribute( 'tag' )}` ) }
showLogin = showLogin.after( log )
document.getElementById( 'button' ).onclick = shoLogin
|
3、例子:用 AOP 动态改变函数的参数
1 2 3 4 5 6 7 8 9
| const func = param => { console.log( param ) }
func = func.before(param => { param.b = 'b' })
func( {a: 'a'} )
|
4、例子:插件式的表单验证
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
| Function.prototype.before = function( beforefn ) { const _self = this; return () => { if ( beforefn.apply( this, arguments ) === false ) { return } return _self.apply( this, arguments ) } }
const validata = () => { if ( username.value === '' ) { alert ( '用户名不能为空' ) return false } if ( password.value === '' ) { alert ( '密码不能为空' ) return false } }
const formSubmit = () => { const param = { username: username.value, password: password.value } ajax( 'http://xxx.com/login', param ) }
formSubmit = formSubmit.before( validata )
submitBtn.onclick = () => { fromSubmit() }
|
5、注意
被装饰过的函数,返回的实际上是一个新的函数,如果在原函数上保存了一些属性,那么这些属性会丢失。
1 2 3 4 5 6 7 8 9 10
| const func = () => { alert( 1 ) } func.a = 'a'
func = func.after(()=>{ alert( 2 ) })
alert( func.a )
|
6、装饰者模式与代理模式
最重要的区别是意图和设计目的。
在虚拟代理实现预图片加载的例子中,本体负责设置 img 节点的 src,代理则提供了预加载的功能,这看起来也是“加入行为”的一种方式,但这种方式和装饰者模式的偏重点不一样。装饰者模式是实实在在的为对象增加新的职责和行为,而代理模式的事情还是跟本体一样,最终都是设置src。但代理加入了一些“聪明”的功能,比如在图片真正加载好之前,先使用一张占位的loading图片反馈给客户。