锁定老帖子 主题:JS:惰性函数定义?不是最优化方案
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2007-08-17
Lazy Function Definition Pattern
js函数式编程中的一种设计模式 http://realazy.org/blog/2007<wbr></wbr>/08/16/lazy-function-definitio<wbr></wbr>n-pattern/ 惰性函数定义模式的中文翻译 我认为没什么用,还有内存泄露,我这样写 function foo() { return this.date||(this.date=Date()); return foo.date||(foo.date=Date()); }; 或 function foo(){ var c=arguments.callee; return c.date=c.date||Date(); } 或 my={ foo:function () { return this._date||(this._date=Date()); } } 或约定一下 var _foo_date; function foo(){ return _foo_date=_foo_date||Date(); } 1.代码精悍 2.没有泄露 这种小对象的内存泄露一般不会很大,可以忽略. 当作用于有大量子元素的dom节点时,这种泄漏就会累加到一个恐怖的地步.对于类似GoogleReader这类应用常常会遇到类似问题 3.解决了foo每次调用所带来的条件求值 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2007-08-17
我只能用作者的话回复你:
Your example is nice and short and you don’t refer to foo twice. I debated about using a a couple different compact forms for the warm-up exercise but solutions in real examples never seem take the same compact forms. |
|
返回顶楼 | |
发表时间:2007-08-17
hax 说的“内存泄漏”仅是实现层的问题。而LZ的代码根本就是错的,其实用了一个全局变量:
js> date = 9 9 js> function foo() { return this.date||(this.date=Date()); }; js> foo() 9 还不如方案一。就算运气好点,原本 date 为一个假值,this 引用也会污染上层名字空间。 js> date = 0 0 js> foo() Fri Aug 17 2007 20:30:42 GMT+0800 (CST) js> date Fri Aug 17 2007 20:30:42 GMT+0800 (CST) 看得我都有从 javascript研究小组 退组的想法了。 To hax: Lazy 版函数决不是什么新东西,但性能消耗还没上升到人人喊打的地步,安全性是值得称赞的。 |
|
返回顶楼 | |
发表时间:2007-08-18
错误已修正
|
|
返回顶楼 | |
发表时间:2007-08-18
zuroc 写道 错误已修正
本质上没变啊,只是把这个名字空间换成了那个名字空间而已,等同相当于方案三,或者更怪。 JS1.5 中只有闭包代换才能保证安全,一点类似 Lich_Ray 给出的纯恶搞的代码就能崩了它,所以祈祷吧 |
|
返回顶楼 | |
发表时间:2007-08-18
楼主确实原来犯了一个低级错误,呵呵。
此外,用 || 短路操作,存在一个问题,就是计算结果可能为false, 0, null, ''的情况,结果每次调用都会重新计算一遍。当然这个Date的小例子里不存在,但是很值得警惕哦。所以比较严谨的写法,还是不要省略这若干个字符,写成: if ('_cache' in argument.callee) return argument.callee._cache; To Realazy: 在我之后,fckeditor的人好像有个回帖,意思跟我接近。Peter自己有回帖,表示要update,你可以看看,是否也更新一下你的翻译,呵呵。 To Lich_Ray: 不是我要跟你较真,但这个closure内存泄露,不单单是实现层的问题。一个是,ECMA规范里完全没有要求对这种情况的优化。因此编程的前提若是这种不太可靠的优化,就不是很妥当,事实上,现在似乎也没有js引擎做了这种优化。我个人猜测,编译型的js引擎,比较可能去作这种优化,例如rhino的编译成java类,以及actionscript,谁有兴趣可以去测试看看。 而就算一个最出色的优化过的引擎,只要closure内部存在动态eval,理论上所有scopechain上的变量都不可能被优化掉。 所以从当前实践的角度出发,这种内存泄露,是编程造成的。只能希望以后,我们可以没有这个负担。 另外,我没有说过这个方法性能消耗大到人人喊大,我只是指出这个方法并没有提供什么性能优势,同时容易造成内存泄露的事实。关于你说的安全性,我猜测你是指function对象上的cache可能被外部代码破坏。不错,理论上确实如此,但实际中,通过一个良好的命名规范,是可以在实践上避免的。 况且,我只是指出问题,并没有完全否定closure的使用。在实际编程中,我也一样疯狂的使用closure,一样疯狂的热爱functional的方式。我所在开发的PIES框架中,核心的module/package功能就是靠创造许多的closure,再用上许多邪恶的with来达到的。 我所表达的意思,其实无非是使用closure的时候你也要注意一下,有些时候没有必要一定用closure,有些时候需要谨慎考虑一下closure外面变量的生命周期。 还有,说到functional,其实像重新改写自身(改变了binding)这种事情,是违背functional的精神的。这也是我对于qomo的AOP实现的批评之一,它悄悄的把你的方法给替换了,名字一样,表面看上去没有变化,但对象已经不是那个对象了(放在现实世界中可以拍电影了,参考《face off》,呵呵)。这种事情其实是存在危险的。 BTW,楼主虽然犯了低级错误,但也不至于拿退出js圈子相威胁吧?你咋不宣称要退出javaeye呢,呵呵? |
|
返回顶楼 | |
发表时间:2007-08-18
Beag.Ye 写道 zuroc 写道 错误已修正
本质上没变啊,只是把这个名字空间换成了那个名字空间而已,等同相当于方案三,或者更怪。 JS1.5 中只有闭包代换才能保证安全,一点类似 Lich_Ray 给出的纯恶搞的代码就能崩了它,所以祈祷吧 js中无法限制写纯恶搞的代码,如下,还是在服务器端限制吧 var foo=function (){ alert("正常运行") } document.body.onclick=foo //恶意代码 var foo=function (){ alert("黑客入侵") } document.body.onclick=foo |
|
返回顶楼 | |
发表时间:2007-08-18
首先我是从ajaxian看到这篇文章呢。这个标题太容易让人误解,和FP没什么关系。
我觉得可以分为两个层面内容: 1、cache。你的date无论怎么看都是一个cahce的应用。当第一次得到结果时,计算值。 这种情况,cache放到哪我觉得无所谓。是约定问题。当系统中有大量的这种应用时,放心,自然而然 解决cache的模式就有了。 2、getScollX那个应用和date的不同,而是自己修改自己,不重在名称空间污染的情况。 |
|
返回顶楼 | |
发表时间:2007-08-18
function outerFun(a){
function innerFun(p){ return a+p; } return function(p){ return innerFun(p); } } alert(outerFun(2)(2)) //最理想用法 var f=outerFun(3); //这样用呢 var f1=outerFun(4); //这样用呢 hax 说的性能问题是这吗? alert(f(2)) alert(f1(2)) 无closure,无innerFunction的代码性能最高? 如果把所有附值语句都去掉呢? 谁最节约内存呢? |
|
返回顶楼 | |
发表时间:2007-08-18
我在最近几个帖子里谈到过性能问题只有以下几个:
1. 这个在第一次调用时重新定义自己的pattern,不可能带来 significant 的性能提升(如果不是反而降低的话)。 2. 如果我没有记错,根据 Brendan Eich 的说法,总体来说closure比通常方法要多耗三倍内存,慢三倍。至于他是怎么得出这个结论的,请自行mail问之。不过鉴于他的身份,偶是比较相信他的话的。 3. 关于closure对垃圾回收的影响,请阅读我的帖子:http://hax.iteye.com/blog/113565 |
|
返回顶楼 | |