<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>
<channel>
	<title>Comments on: 惰性函数定义模式</title>
	<atom:link href="http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/feed/" rel="self" type="application/rss+xml" />
	<link>http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/</link>
	<description>web 标准，前端开发，编程感悟，生活杂想</description>
	<pubDate>Thu, 20 Nov 2008 23:26:19 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.5.1</generator>
		<item>
		<title>By: s79</title>
		<link>http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-62730</link>
		<dc:creator>s79</dc:creator>
		<pubDate>Sat, 03 May 2008 19:10:09 +0000</pubDate>
		<guid isPermaLink="false">http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-62730</guid>
		<description>@JSFans
return foo()是为了让第一次调用的时候有返回值。第一次改变了foo的引用，也要返回值。当然写成return foo() 还不如直接return t 简明。
@x16manx
方法三把t作为对象foo（这个对象是个函数）的属性，所以得以保存。就像全局变量（其实相当于window的属性）能被保存下来一样。也就是说只要能找到foo，就能找到foo.t，不会被回收。
hax说的Cache就是把t保存下来的意思。

其实这样保存和使用全局变量保存t，本质上是一样的。都使用了不必要的public变量或属性。个人认为闭包保存私有变量是最好方法。</description>
		<content:encoded><![CDATA[<p>@JSFans<br />
return foo()是为了让第一次调用的时候有返回值。第一次改变了foo的引用，也要返回值。当然写成return foo() 还不如直接return t 简明。<br />
@x16manx<br />
方法三把t作为对象foo（这个对象是个函数）的属性，所以得以保存。就像全局变量（其实相当于window的属性）能被保存下来一样。也就是说只要能找到foo，就能找到foo.t，不会被回收。<br />
hax说的Cache就是把t保存下来的意思。</p>
<p>其实这样保存和使用全局变量保存t，本质上是一样的。都使用了不必要的public变量或属性。个人认为闭包保存私有变量是最好方法。</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: x16manx</title>
		<link>http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-62220</link>
		<dc:creator>x16manx</dc:creator>
		<pubDate>Thu, 01 May 2008 05:31:40 +0000</pubDate>
		<guid isPermaLink="false">http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-62220</guid>
		<description>To JSFans: 关于return foo();

return是为了完成函数的重定义. return foo()是为了在函数内部就完成了对函数重定义的第一次调用.

你可以这么理解.

如果我们在函数内部.只是return foo;这样也是可以的.

但是,在外部调用的时候,我们就要写两次foo()的调用,才能达到我们想要的重定义以后的函数的执行.
foo();//第一次,仅仅完成函数的重定义.
foo();//第二次,真真的执行重定义以后的新函数.

很显然,这样不够好,所以就将return foo();放在了函数内部.这样在外面的第一调用就已经是
在执行重定义以后的新函数了.

还有,我对于方法三,理解上也比较吃力.  为什么在函数执行后,原来的对象属性还存在着呢.
这个怎么和闭环对应上呢.Cache就更不理解了.

谁来解惑啊.</description>
		<content:encoded><![CDATA[<p>To JSFans: 关于return foo();</p>
<p>return是为了完成函数的重定义. return foo()是为了在函数内部就完成了对函数重定义的第一次调用.</p>
<p>你可以这么理解.</p>
<p>如果我们在函数内部.只是return foo;这样也是可以的.</p>
<p>但是,在外部调用的时候,我们就要写两次foo()的调用,才能达到我们想要的重定义以后的函数的执行.<br />
foo();//第一次,仅仅完成函数的重定义.<br />
foo();//第二次,真真的执行重定义以后的新函数.</p>
<p>很显然,这样不够好,所以就将return foo();放在了函数内部.这样在外面的第一调用就已经是<br />
在执行重定义以后的新函数了.</p>
<p>还有,我对于方法三,理解上也比较吃力.  为什么在函数执行后,原来的对象属性还存在着呢.<br />
这个怎么和闭环对应上呢.Cache就更不理解了.</p>
<p>谁来解惑啊.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: hax</title>
		<link>http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-29609</link>
		<dc:creator>hax</dc:creator>
		<pubDate>Fri, 17 Aug 2007 18:52:43 +0000</pubDate>
		<guid isPermaLink="false">http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-29609</guid>
		<description>刚刚洗了个澡，想到似乎有点地方不够严谨，上来补充一下。

一个是，是否有js引擎做了优化可以把closure没有用到的变量对象回收掉，也许某些编译型js引擎会作这种优化，但是我没有测试过。
另一个，改写函数本身是存在一定风险的（例如在第一次调用之前，有人持有了对该方法的引用，而第一次调用又恰好存在某种影响条件的副作用）。
而且也违背functional的精神（纯fp中不会存在重新binding的事情）。</description>
		<content:encoded><![CDATA[<p>刚刚洗了个澡，想到似乎有点地方不够严谨，上来补充一下。</p>
<p>一个是，是否有js引擎做了优化可以把closure没有用到的变量对象回收掉，也许某些编译型js引擎会作这种优化，但是我没有测试过。<br />
另一个，改写函数本身是存在一定风险的（例如在第一次调用之前，有人持有了对该方法的引用，而第一次调用又恰好存在某种影响条件的副作用）。<br />
而且也违背functional的精神（纯fp中不会存在重新binding的事情）。</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: JSFans</title>
		<link>http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-29602</link>
		<dc:creator>JSFans</dc:creator>
		<pubDate>Fri, 17 Aug 2007 14:46:59 +0000</pubDate>
		<guid isPermaLink="false">http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-29602</guid>
		<description>我是初学，看了第四种的写法，有几个地方不明白，我很想弄明白，希望能解释一下。问题是这样的：函数内是对foo方法的重新定义吧？如果是的话，我们直接在调用函数的时候foo()不就完成对新方法的调用了吗？为什么还要加上reutrn foo()呢？我也知道，没有return foo()会出错，可还是想不通这句话的作用。再有楼主说这么写“只会简单地返回t保留在其闭包内的值”，可每次返回的时间都是不同的，这样不还是等同于重新计算一次时间了吗？还是我的理解错误。别见笑我的问题，盼望你的解答，谢谢。</description>
		<content:encoded><![CDATA[<p>我是初学，看了第四种的写法，有几个地方不明白，我很想弄明白，希望能解释一下。问题是这样的：函数内是对foo方法的重新定义吧？如果是的话，我们直接在调用函数的时候foo()不就完成对新方法的调用了吗？为什么还要加上reutrn foo()呢？我也知道，没有return foo()会出错，可还是想不通这句话的作用。再有楼主说这么写“只会简单地返回t保留在其闭包内的值”，可每次返回的时间都是不同的，这样不还是等同于重新计算一次时间了吗？还是我的理解错误。别见笑我的问题，盼望你的解答，谢谢。</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: 张沈鹏</title>
		<link>http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-29596</link>
		<dc:creator>张沈鹏</dc:creator>
		<pubDate>Fri, 17 Aug 2007 11:08:33 +0000</pubDate>
		<guid isPermaLink="false">http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-29596</guid>
		<description>惰性函数定义?不是最优化方案
http://zsp.javaeye.com/blog/113579</description>
		<content:encoded><![CDATA[<p>惰性函数定义?不是最优化方案<br />
<a href="http://zsp.javaeye.com/blog/113579" rel="nofollow">http://zsp.javaeye.com/blog/113579</a></p>
]]></content:encoded>
	</item>
	<item>
		<title>By: 张沈鹏</title>
		<link>http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-29595</link>
		<dc:creator>张沈鹏</dc:creator>
		<pubDate>Fri, 17 Aug 2007 11:02:46 +0000</pubDate>
		<guid isPermaLink="false">http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-29595</guid>
		<description>function foo() {
    return this.date&#124;&#124;(this.date=Date());
};</description>
		<content:encoded><![CDATA[<p>function foo() {<br />
    return this.date||(this.date=Date());<br />
};</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: hax</title>
		<link>http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-29592</link>
		<dc:creator>hax</dc:creator>
		<pubDate>Fri, 17 Aug 2007 10:21:54 +0000</pubDate>
		<guid isPermaLink="false">http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-29592</guid>
		<description>To lich ray:

为什么很难做闭包优化，这和js的一些特点有关，请看我javaeye上的最新一篇blog的最后一段。简单来说：eval可能会动态访问任何变量，with可以动态的影响scope。</description>
		<content:encoded><![CDATA[<p>To lich ray:</p>
<p>为什么很难做闭包优化，这和js的一些特点有关，请看我javaeye上的最新一篇blog的最后一段。简单来说：eval可能会动态访问任何变量，with可以动态的影响scope。</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Lich_Ray</title>
		<link>http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-29590</link>
		<dc:creator>Lich_Ray</dc:creator>
		<pubDate>Fri, 17 Aug 2007 10:14:24 +0000</pubDate>
		<guid isPermaLink="false">http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-29590</guid>
		<description>确实，就优化难度上来说，优化同一布尔表达式的反复求值比优化闭包要常见地多。
不过文章给出的思想确实是可行的，风格也没什么问题，而且最重要的是，很安全。</description>
		<content:encoded><![CDATA[<p>确实，就优化难度上来说，优化同一布尔表达式的反复求值比优化闭包要常见地多。<br />
不过文章给出的思想确实是可行的，风格也没什么问题，而且最重要的是，很安全。</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: hax</title>
		<link>http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-29584</link>
		<dc:creator>hax</dc:creator>
		<pubDate>Fri, 17 Aug 2007 09:05:51 +0000</pubDate>
		<guid isPermaLink="false">http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-29584</guid>
		<description>realazy同志，吹捧的话我就不说了。俺说点不中听的。

首先我觉得你这篇文章所讨论的方法并不宜称之为惰性函数定义。实际上我第一次看到这个标题，我以为你打算在js中使用一种模拟lazy evaluation的技术，但实际上并非如此。在我的印象中，lazy译作惰性，常见于惰性求值，而"惰性函数"我们会理解为使用惰性求值的函数。所以你的"惰性函数定义"的名字容易造成歧义。

其次我觉得你所说的方法与lazy initialization（http://en.wikipedia.org/wiki/Lazy_initialization）并无本质区别，只是js对象可以改写，所以你改写后避免了一次判断。

下面，我要泼一点冷水。我认为这一技巧在绝大多数场合是没有什么特别优点的，相反存在着陷阱。

在目前所有的js引擎中，一次判断的性能开销与其他开销（例如一次函数调用的开销）相比，根本不在一个数量级上。而你所说的"如果之前那些条件非常多和复杂的话"，这个假设是错误的，因为并不需要每次都进行非常多和复杂的条件判断——方法三本质上是一个cache模式。如果这些条件逻辑上每次都需要重新计算，那也不可能去使用你的“函数重新定义自身”的方法。

注意，对于方法三的运用来说，你前面的示例和后面的getScrollY其实有一定的不同。前者是直接缓存函数的运算结果，后者则需要缓存函数分支条件。相对来说后者看上去更适合用你的"函数重新定义自身"的方法，而前者则相反。

在"缓存运算结果"的case里，方法四的实际效率比方法三更低。我们来分析一下：

第一次调用时，方法三需要一次boolean判断，然后运算，然后缓存结果（一次对local的赋值），然后返回结果。方法四需要运算，然后产生一个闭包，重新定义自己（一次对外层scope的赋值），然后再调用一次自身，返回调用结果。

可见，第一次调用的时候，肯定是方法三快。

再看以后的调用，方法三需要一次boolean判断，然后返回缓存结果。方法四直接返回结果。

看上去方法四会快，但是注意，方法三的缓存结果是在local上，而方法四，是在外面一层的scope上，因此变量搜索上，理论上方法三会比方法四快一点。当然变量搜索的开销其实是很小的，但反过来，boolean判断的开销也是非常小的。因此很难说方法四就比方法三快，即使快，也快得非常有限，可以忽略不计。

但是方法四，其实存在另一方面的问题。

在方法三中，如果有很多的中间运算结果，在第一次运行后，这些结果都会被自动回收回去。而方法四中，由于替换自身的闭包对于被替换的方法内的所有变量都存在引用，因此这些变量所指向的对象全部不会被回收回去！！除非你手动把变量设置为null——手动清空显然不是什么好模式。

当然理论上，在闭包中没有明确用到的外部变量其实可以不影响垃圾回收（除非在闭包中存在eval之类的东西），但是目前我已知的主流js引擎似乎都没有做这方面的优化。因此，不恰当的使用方法四，会造成内存泄漏。即使在getScrollY的例子中，根本不存在任何局部变量，其所产生的闭包中也不存在任何原本方法的可能的引用，但实际上原方法仍是不会被回收的。如果你要测试的话，可以在第一次调用前执行getScrollY.wasteMemory = new Array(100000).join('foobar');然后观察浏览器的内存在第一次调用后是否就减小了。我虽然没有实测过，但是根据经验，结果应该是不会释放这些内存的。而且在第一次调用之后，你甚至再也没有机会去释放这个内存，呵呵。

值得注意的是，这并非浏览器bug造成的内存泄漏，而只是由于缺乏优化而造成的泄漏。

所以你的这个模式恐怕既不健壮，也不高效，至于说是不是紧凑呢，我自己是没看出来方法四比方法三紧凑在哪里。而且就这个模式本身来说，并没有用到很functional的技巧。

BTW，我看到最后发现是翻译的。。。不知道你有没有兴趣把我的回复翻译回去贴到原出处去，呵呵。</description>
		<content:encoded><![CDATA[<p>realazy同志，吹捧的话我就不说了。俺说点不中听的。</p>
<p>首先我觉得你这篇文章所讨论的方法并不宜称之为惰性函数定义。实际上我第一次看到这个标题，我以为你打算在js中使用一种模拟lazy evaluation的技术，但实际上并非如此。在我的印象中，lazy译作惰性，常见于惰性求值，而&#8221;惰性函数&#8221;我们会理解为使用惰性求值的函数。所以你的&#8221;惰性函数定义&#8221;的名字容易造成歧义。</p>
<p>其次我觉得你所说的方法与lazy initialization（http://en.wikipedia.org/wiki/Lazy_initialization）并无本质区别，只是js对象可以改写，所以你改写后避免了一次判断。</p>
<p>下面，我要泼一点冷水。我认为这一技巧在绝大多数场合是没有什么特别优点的，相反存在着陷阱。</p>
<p>在目前所有的js引擎中，一次判断的性能开销与其他开销（例如一次函数调用的开销）相比，根本不在一个数量级上。而你所说的&#8221;如果之前那些条件非常多和复杂的话&#8221;，这个假设是错误的，因为并不需要每次都进行非常多和复杂的条件判断——方法三本质上是一个cache模式。如果这些条件逻辑上每次都需要重新计算，那也不可能去使用你的“函数重新定义自身”的方法。</p>
<p>注意，对于方法三的运用来说，你前面的示例和后面的getScrollY其实有一定的不同。前者是直接缓存函数的运算结果，后者则需要缓存函数分支条件。相对来说后者看上去更适合用你的&#8221;函数重新定义自身&#8221;的方法，而前者则相反。</p>
<p>在&#8221;缓存运算结果&#8221;的case里，方法四的实际效率比方法三更低。我们来分析一下：</p>
<p>第一次调用时，方法三需要一次boolean判断，然后运算，然后缓存结果（一次对local的赋值），然后返回结果。方法四需要运算，然后产生一个闭包，重新定义自己（一次对外层scope的赋值），然后再调用一次自身，返回调用结果。</p>
<p>可见，第一次调用的时候，肯定是方法三快。</p>
<p>再看以后的调用，方法三需要一次boolean判断，然后返回缓存结果。方法四直接返回结果。</p>
<p>看上去方法四会快，但是注意，方法三的缓存结果是在local上，而方法四，是在外面一层的scope上，因此变量搜索上，理论上方法三会比方法四快一点。当然变量搜索的开销其实是很小的，但反过来，boolean判断的开销也是非常小的。因此很难说方法四就比方法三快，即使快，也快得非常有限，可以忽略不计。</p>
<p>但是方法四，其实存在另一方面的问题。</p>
<p>在方法三中，如果有很多的中间运算结果，在第一次运行后，这些结果都会被自动回收回去。而方法四中，由于替换自身的闭包对于被替换的方法内的所有变量都存在引用，因此这些变量所指向的对象全部不会被回收回去！！除非你手动把变量设置为null——手动清空显然不是什么好模式。</p>
<p>当然理论上，在闭包中没有明确用到的外部变量其实可以不影响垃圾回收（除非在闭包中存在eval之类的东西），但是目前我已知的主流js引擎似乎都没有做这方面的优化。因此，不恰当的使用方法四，会造成内存泄漏。即使在getScrollY的例子中，根本不存在任何局部变量，其所产生的闭包中也不存在任何原本方法的可能的引用，但实际上原方法仍是不会被回收的。如果你要测试的话，可以在第一次调用前执行getScrollY.wasteMemory = new Array(100000).join(&#8217;foobar&#8217;);然后观察浏览器的内存在第一次调用后是否就减小了。我虽然没有实测过，但是根据经验，结果应该是不会释放这些内存的。而且在第一次调用之后，你甚至再也没有机会去释放这个内存，呵呵。</p>
<p>值得注意的是，这并非浏览器bug造成的内存泄漏，而只是由于缺乏优化而造成的泄漏。</p>
<p>所以你的这个模式恐怕既不健壮，也不高效，至于说是不是紧凑呢，我自己是没看出来方法四比方法三紧凑在哪里。而且就这个模式本身来说，并没有用到很functional的技巧。</p>
<p>BTW，我看到最后发现是翻译的。。。不知道你有没有兴趣把我的回复翻译回去贴到原出处去，呵呵。</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: g-carton</title>
		<link>http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-29573</link>
		<dc:creator>g-carton</dc:creator>
		<pubDate>Fri, 17 Aug 2007 06:20:43 +0000</pubDate>
		<guid isPermaLink="false">http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-29573</guid>
		<description>看不大懂,还没学到这个东西呢~
不过感觉第二段代码的写法很独特~呵呵！</description>
		<content:encoded><![CDATA[<p>看不大懂,还没学到这个东西呢~<br />
不过感觉第二段代码的写法很独特~呵呵！</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: shqlsl</title>
		<link>http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-29572</link>
		<dc:creator>shqlsl</dc:creator>
		<pubDate>Fri, 17 Aug 2007 05:37:07 +0000</pubDate>
		<guid isPermaLink="false">http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-29572</guid>
		<description>我做了一个测试... 非常棒

			
			</description>
		<content:encoded><![CDATA[<p>我做了一个测试&#8230; 非常棒</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: shqlsl</title>
		<link>http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-29571</link>
		<dc:creator>shqlsl</dc:creator>
		<pubDate>Fri, 17 Aug 2007 05:32:39 +0000</pubDate>
		<guid isPermaLink="false">http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-29571</guid>
		<description>非常的棒.  特别 第二次运行... 真的好办.  对于只有一次运行来说没啥效果...
 你能不能给一个效率对比的... 天天关注你的博客</description>
		<content:encoded><![CDATA[<p>非常的棒.  特别 第二次运行&#8230; 真的好办.  对于只有一次运行来说没啥效果&#8230;<br />
 你能不能给一个效率对比的&#8230; 天天关注你的博客</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: aw</title>
		<link>http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-29557</link>
		<dc:creator>aw</dc:creator>
		<pubDate>Fri, 17 Aug 2007 01:59:58 +0000</pubDate>
		<guid isPermaLink="false">http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-29557</guid>
		<description>脚本语言的函数实在是博大精深到了极致。</description>
		<content:encoded><![CDATA[<p>脚本语言的函数实在是博大精深到了极致。</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: qinyf</title>
		<link>http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-29512</link>
		<dc:creator>qinyf</dc:creator>
		<pubDate>Thu, 16 Aug 2007 09:44:06 +0000</pubDate>
		<guid isPermaLink="false">http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-29512</guid>
		<description>看到第一眼以为是你自创的函数，哈哈。
内容赞一下</description>
		<content:encoded><![CDATA[<p>看到第一眼以为是你自创的函数，哈哈。<br />
内容赞一下</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: iWorm</title>
		<link>http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-29491</link>
		<dc:creator>iWorm</dc:creator>
		<pubDate>Thu, 16 Aug 2007 05:09:21 +0000</pubDate>
		<guid isPermaLink="false">http://realazy.org/blog/2007/08/16/lazy-function-definition-pattern/#comment-29491</guid>
		<description>嗯, 写的不错.
懒人用懒惰模式. 哈哈哈</description>
		<content:encoded><![CDATA[<p>嗯, 写的不错.<br />
懒人用懒惰模式. 哈哈哈</p>
]]></content:encoded>
	</item>
</channel>
</rss>
