<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>idv2 &#187; greasemonkey</title>
	<atom:link href="http://tech.idv2.com/tag/greasemonkey/feed/" rel="self" type="application/rss+xml" />
	<link>http://tech.idv2.com</link>
	<description>关注Web开发技术，关注Internet。</description>
	<lastBuildDate>Tue, 27 Jul 2010 12:54:54 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.5</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>[GreaseMonkey]如何hook已有函数</title>
		<link>http://tech.idv2.com/2009/03/16/hook-function-in-greasemonkey/</link>
		<comments>http://tech.idv2.com/2009/03/16/hook-function-in-greasemonkey/#comments</comments>
		<pubDate>Mon, 16 Mar 2009 02:54:37 +0000</pubDate>
		<dc:creator>charlee</dc:creator>
				<category><![CDATA[web]]></category>
		<category><![CDATA[firefox]]></category>
		<category><![CDATA[greasemonkey]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://tech.idv2.com/2009/03/16/hook-function-in-greasemonkey/</guid>
		<description><![CDATA[<!-- begin Pukiwiki generated code--><p>GreaseMonkey这个插件大家都早已熟悉了。最近我遇到一个问题：需要让页面在调用完某个函数之后自动执行我的函数。
其实这个并不难，写个函数替换原有的函数即可：</p>
<pre>function hook() {
  var f = unsafeWindow.foo;         // 保存旧函数
  unsafeWindow.foo = function() {   // 定义新函数
    alert(&quot;Hello!&quot;);                // 先执行我们的处理
    f();                            // 再执行旧函数
  }
}</pre>
<p>然后加载到页面上：</p>
<pre>setTimeout(hook, 1000);</pre>
<p>这样，页面再执行foo函数时，就会先执行我们的alert(&quot;Hello!&quot;)了。</p>
<p>不过这个函数还有很大的问题。比如，原有函数的参数不能正确传给foo，返回值无法取出来，无法应用到对象中的方法，通用性不好等。
下面来一个个解决。</p>
<!-- end Pukiwiki generated code--><span id="more-686"></span><!-- begin Pukiwiki generated code--><p>返回值的问题比较好办，让它return一下就行了：</p>
<pre>function hook() {
  var f = unsafeWindow.foo;         // 保存旧函数
  unsafeWindow.foo = function() {   // 定义新函数
    alert(&quot;Hello!&quot;);                // 先执行我们的处理
    return f();                     // 再执行旧函数
}</pre>
<p>对象方法的意思是，如果要hook的函数不是全局函数，而是某个对象的方法的话，上述函数就无法正确执行。</p>
<pre>var object = {
  value: 10,
  foo: function () { alert(&quot;Foo!&quot; + this.value); }
};
object.foo();</pre>
<p>此时如果只是简单修改一下最初的GreaseMonkey脚本，改成这样的话：</p>
<pre>// 注意这种实现方法是错误的！
function hook() {
  var f = unsafeWindow.object.foo;         // 保存旧函数
  unsafeWindow.object.foo = function() {   // 定义新函数
    alert(&quot;Hello!&quot;);                       // 先执行我们的处理
    return f();                            // 再执行旧函数
  }
}</pre>
<p>那么执行foo()时你会发现，本应输出&quot;Foo!10&quot;，但实际输出结果变成了&quot;Foo!undefined&quot;。
这是因为临时保存下来的 f 函数在执行时没有绑定到unsafeWindow.object上，因此找不到this.value。</p>
<p>解决方法是在调用 f 时使用 apply：</p>
<pre>// 正确的方法
function hook() {
  var f = unsafeWindow.object.foo;         // 保存旧函数
  unsafeWindow.object.foo = function() {   // 定义新函数
    alert(&quot;Hello!&quot;);                       // 先执行我们的处理
    return f.apply(unsafeWindow.object);   // 再执行旧函数
  }
}</pre>
<p>有了apply，参数问题也迎刃而解：</p>
<pre>function hook() {
  var f = unsafeWindow.object.foo;                    // 保存旧函数
  unsafeWindow.object.foo = function() {              // 定义新函数
    alert(&quot;Hello!&quot;);                                  // 先执行我们的处理
    return f.apply(unsafeWindow.object, arguments);   // 再执行旧函数
  }
}</pre>
<p>最后的问题就是这个函数通用性还不好。代码中把要hook的函数(unsafeWindow.object.foo)写死了，
这样每hook一个函数都要写专用的函数才行。下面试着让它通用一些：</p>
<pre>/**
 * hook系统中的已有函数
 * @param object {Object} 要hook的函数所在的对象
 * @param name {String} 要hook的函数名称
 * @param pre {Function} 原函数执行前要执行的动作
 * @param post {Function} 原函数执行后要执行的动作
 * @return 旧函数的返回值
 */
function hook(object, func, pre, post) {
  var f = object[func];                       // 保存旧函数
  object[func] = function() {                 // 定义新函数
    if (pre) pre.apply(window, arguments);    // 旧函数执行前执行的自定义函数
    var ret = f.apply(object, arguments);     // 执行旧函数
    if (post) post.apply(window, arguments);  // 旧函数执行后执行的自定义函数
    return ret;
  }
}</pre>
<p>这样这个函数就相当通用了。在hook时需要执行以下代码：</p>
<pre>setTimeout(function() {
  hook(unsafeWindow.object, 
       &quot;foo&quot;, 
       function(){alert(&quot;pre&quot;)}, 
       function(){alert(&quot;post&quot;)}
  );
}, 1000);</pre>
<p>当然上述函数还有可以改进的地方。如调用pre和post时直接apply到了window上，
这样如果在hook时给出的pre和post不是全局函数而是某个对象的方法的话，
函数就无法正常执行了。不过对于一般的应用来说，上面的方法已经足够了吧。</p>
<!-- end Pukiwiki generated code-->
]]></description>
			<content:encoded><![CDATA[<!-- begin Pukiwiki generated code--><p>GreaseMonkey这个插件大家都早已熟悉了。最近我遇到一个问题：需要让页面在调用完某个函数之后自动执行我的函数。
其实这个并不难，写个函数替换原有的函数即可：</p>
<pre>function hook() {
  var f = unsafeWindow.foo;         // 保存旧函数
  unsafeWindow.foo = function() {   // 定义新函数
    alert(&quot;Hello!&quot;);                // 先执行我们的处理
    f();                            // 再执行旧函数
  }
}</pre>
<p>然后加载到页面上：</p>
<pre>setTimeout(hook, 1000);</pre>
<p>这样，页面再执行foo函数时，就会先执行我们的alert(&quot;Hello!&quot;)了。</p>
<p>不过这个函数还有很大的问题。比如，原有函数的参数不能正确传给foo，返回值无法取出来，无法应用到对象中的方法，通用性不好等。
下面来一个个解决。</p>
<!-- end Pukiwiki generated code--><span id="more-686"></span><!-- begin Pukiwiki generated code--><p>返回值的问题比较好办，让它return一下就行了：</p>
<pre>function hook() {
  var f = unsafeWindow.foo;         // 保存旧函数
  unsafeWindow.foo = function() {   // 定义新函数
    alert(&quot;Hello!&quot;);                // 先执行我们的处理
    return f();                     // 再执行旧函数
}</pre>
<p>对象方法的意思是，如果要hook的函数不是全局函数，而是某个对象的方法的话，上述函数就无法正确执行。</p>
<pre>var object = {
  value: 10,
  foo: function () { alert(&quot;Foo!&quot; + this.value); }
};
object.foo();</pre>
<p>此时如果只是简单修改一下最初的GreaseMonkey脚本，改成这样的话：</p>
<pre>// 注意这种实现方法是错误的！
function hook() {
  var f = unsafeWindow.object.foo;         // 保存旧函数
  unsafeWindow.object.foo = function() {   // 定义新函数
    alert(&quot;Hello!&quot;);                       // 先执行我们的处理
    return f();                            // 再执行旧函数
  }
}</pre>
<p>那么执行foo()时你会发现，本应输出&quot;Foo!10&quot;，但实际输出结果变成了&quot;Foo!undefined&quot;。
这是因为临时保存下来的 f 函数在执行时没有绑定到unsafeWindow.object上，因此找不到this.value。</p>
<p>解决方法是在调用 f 时使用 apply：</p>
<pre>// 正确的方法
function hook() {
  var f = unsafeWindow.object.foo;         // 保存旧函数
  unsafeWindow.object.foo = function() {   // 定义新函数
    alert(&quot;Hello!&quot;);                       // 先执行我们的处理
    return f.apply(unsafeWindow.object);   // 再执行旧函数
  }
}</pre>
<p>有了apply，参数问题也迎刃而解：</p>
<pre>function hook() {
  var f = unsafeWindow.object.foo;                    // 保存旧函数
  unsafeWindow.object.foo = function() {              // 定义新函数
    alert(&quot;Hello!&quot;);                                  // 先执行我们的处理
    return f.apply(unsafeWindow.object, arguments);   // 再执行旧函数
  }
}</pre>
<p>最后的问题就是这个函数通用性还不好。代码中把要hook的函数(unsafeWindow.object.foo)写死了，
这样每hook一个函数都要写专用的函数才行。下面试着让它通用一些：</p>
<pre>/**
 * hook系统中的已有函数
 * @param object {Object} 要hook的函数所在的对象
 * @param name {String} 要hook的函数名称
 * @param pre {Function} 原函数执行前要执行的动作
 * @param post {Function} 原函数执行后要执行的动作
 * @return 旧函数的返回值
 */
function hook(object, func, pre, post) {
  var f = object[func];                       // 保存旧函数
  object[func] = function() {                 // 定义新函数
    if (pre) pre.apply(window, arguments);    // 旧函数执行前执行的自定义函数
    var ret = f.apply(object, arguments);     // 执行旧函数
    if (post) post.apply(window, arguments);  // 旧函数执行后执行的自定义函数
    return ret;
  }
}</pre>
<p>这样这个函数就相当通用了。在hook时需要执行以下代码：</p>
<pre>setTimeout(function() {
  hook(unsafeWindow.object, 
       &quot;foo&quot;, 
       function(){alert(&quot;pre&quot;)}, 
       function(){alert(&quot;post&quot;)}
  );
}, 1000);</pre>
<p>当然上述函数还有可以改进的地方。如调用pre和post时直接apply到了window上，
这样如果在hook时给出的pre和post不是全局函数而是某个对象的方法的话，
函数就无法正常执行了。不过对于一般的应用来说，上面的方法已经足够了吧。</p>
<!-- end Pukiwiki generated code-->
]]></content:encoded>
			<wfw:commentRss>http://tech.idv2.com/2009/03/16/hook-function-in-greasemonkey/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
