论坛首页 Web前端技术论坛

JS:惰性函数定义?不是最优化方案

浏览 7674 次
精华帖 (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每次调用所带来的条件求值
   发表时间: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.
0 请登录后投票
   发表时间: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 版函数决不是什么新东西,但性能消耗还没上升到人人喊打的地步,安全性是值得称赞的。
0 请登录后投票
   发表时间:2007-08-18  
错误已修正
0 请登录后投票
   发表时间:2007-08-18  
zuroc 写道
错误已修正

本质上没变啊,只是把这个名字空间换成了那个名字空间而已,等同相当于方案三,或者更怪。
JS1.5 中只有闭包代换才能保证安全,一点类似 Lich_Ray 给出的纯恶搞的代码就能崩了它,所以祈祷吧
0 请登录后投票
   发表时间: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呢,呵呵?


0 请登录后投票
   发表时间: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
0 请登录后投票
   发表时间:2007-08-18  
首先我是从ajaxian看到这篇文章呢。这个标题太容易让人误解,和FP没什么关系。
我觉得可以分为两个层面内容:
1、cache。你的date无论怎么看都是一个cahce的应用。当第一次得到结果时,计算值。
   这种情况,cache放到哪我觉得无所谓。是约定问题。当系统中有大量的这种应用时,放心,自然而然  解决cache的模式就有了。
2、getScollX那个应用和date的不同,而是自己修改自己,不重在名称空间污染的情况。
0 请登录后投票
   发表时间: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的代码性能最高?
如果把所有附值语句都去掉呢?
谁最节约内存呢?
0 请登录后投票
   发表时间:2007-08-18  
我在最近几个帖子里谈到过性能问题只有以下几个:

1. 这个在第一次调用时重新定义自己的pattern,不可能带来 significant 的性能提升(如果不是反而降低的话)。

2. 如果我没有记错,根据 Brendan Eich 的说法,总体来说closure比通常方法要多耗三倍内存,慢三倍。至于他是怎么得出这个结论的,请自行mail问之。不过鉴于他的身份,偶是比较相信他的话的。

3. 关于closure对垃圾回收的影响,请阅读我的帖子:http://hax.iteye.com/blog/113565
0 请登录后投票
论坛首页 Web前端技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics