Press "Enter" to skip to content

关于Javascript的俩个有趣的探讨

首先祝贺在经历了几乎一天的等待以后. 我的空间商终于把服务器迁到了电信机房, 外加网通CDN加速.

关于事件处理函数引用的一个佐证

之前, 我在分析Javascript的This关键字的时候, 说过, 当使用inline的方式写dom元素的事件处理函数的时候, 采用的是引用的方式. 刚好nullbyte童鞋给我提供了一个很有意思的Case:

<img id="foo" src="xxx" onerror=" alert('error');
    } function foobar() {
          alert('www.laruence.com'); " />
<script>
alert(document.getElementById("foo").onerror);
</script>

在IE下试试看..
不过, FF和Chrome下都不行, 应该是FF和Chrome都会验证html代码的合法性.

Javascript正则的效率

如果你看到有人写Javascript的trim的时候采用了循环的方式,而不是正则的方式, 请不要笑. 人家这可是经验所致, 考虑如下代码的执行时间会是多少?

var matchs = /^(a+)+$/.exec("aaaaaaaaaaaaaaaaaaaaaaaaaaaX");
alert(matchs);

告诉你吧.... 注:以下结果来自看手表估测, 但不影响时间的长度性...另外jsmore的stauren同学也验证了这一结论:

IE8: 30秒
FF3: 28秒
号称目前最快的采用V8引擎的Chrome: 8秒.

这个结果,,,是多么的不可接受啊? 具体原因的分析, 在master regular expression里面有提到过.

NFA和DFA的引擎是有区别的。js/perl/php/java/.net都是NFA引擎。
而DFA与NFA机制上的不同带来5个影响:
1. DFA对于文本串里的每一个字符只需扫描一次,比较快,但特性较少;NFA要翻来覆去吃字符、吐字符,速度慢,但是特性丰富,所以反而应用广泛,当今主要的正则表达式引擎,如Perl、Ruby、Python的re模块、Java和.NET的regex库,都是NFA的。
2. 只有NFA才支持lazy和backreference(后向引用)等特性;
3. NFA急于邀功请赏,所以最左子正则式优先匹配成功,因此偶尔会错过最佳匹配结果;DFA则是“最长的左子正则式优先匹配成功”。
4. NFA缺省采用greedy量词(就是对于/.*/、/\w+/这样的“重复n”次的模式,以贪婪方式进行,尽可能匹配更多字符,直到不得以罢手为止),NFA会优先匹配量词。
5. NFA可能会陷入递归调用的陷阱而表现得性能极差。
backtracking(回朔)
当NFA发现自己吃多了,一个一个往回吐,边吐边找匹配,这个过程叫做backtracking。由于存在这个过程,在NFA匹配过程中,特别是在编写不合理的正则式匹配过程中,文本被反复扫描,效率损失是不小的。明白这个道理,对于写出高效的正则表达式很有帮助。

而对于Javascript中的正则来说, 应该是优先匹配量词, 导致了很深的递归, 形成了性能问题...

17 Comments

  1. 新影吧
    新影吧 November 27, 2012

    能不能提供些javascript正则性能的学习资料来学习呢?说的名词好深奥啊

  2. jonwang
    jonwang May 16, 2012

    现在我用ff11来测试,已经是瞬间相应了,看来这3年的浏览器发展真是迅猛

  3. sking7
    sking7 October 20, 2011

    特别想知道ie和火狐,chome对那句正则如何进行匹配的,算法是怎样的?

  4. piapai
    piapai April 17, 2011

    第二段代码,我自己在火狐4.0和chrome10的版本中测试了一下,ff会报错,错误如下:regular expression too complex

  5. Cherry
    Cherry October 26, 2009

    你的JS也是如此的牛啊

  6. jindw
    jindw October 16, 2009

    够诡异,够专业。

  7. 雪候鸟
    雪候鸟 October 13, 2009

    @toms sorry, 我没有重现出来, 你能把你的代码mail到我的yahoo邮箱么?

  8. toms
    toms October 12, 2009

    b页面history.go(-1)后, a页面onsubmit事件里的任何东西都无法执行, 排除了验证函数错误

  9. toms
    toms October 12, 2009

    求求大侠能不能帮我看个js问题啊,问题如下
    有两个页面a, b 其中a为表单页面b为数据接收页面
    a中的数据表单使用onsubmit事件验证客户端数据有效性, 但如果我在服务器(页面b)上检测到提交上来的数据不符合要求, 我使用history.go(-1), 返回前一个页面后, 在页面a数据表单无法提交(没有报任何js错误), 在表单内回车和点“submit”均无法提交表单, 经检查发现在b页面history.go(-1)回到a页面后, onsubmit事件无法响应, 此问题仅在firefox下出现, 并且firebug和错误控制台均未报出任何js错误,第一次提交的时候所有js都正常运行了的

  10. phppan
    phppan October 1, 2009

    首先,恭喜
    然后,国庆快乐
    最后,虽然把精通正则表达式看过了,但是对此的了解依然不够。学习了

  11. 雪候鸟
    雪候鸟 September 28, 2009

    @cjj 有理, 正则也是一门独立的艺术.

  12. yuehei
    yuehei September 28, 2009

    测试了一下,果然很慢。。以后少用正则,
    可是为什么测试的正则要有两个+号呢
    /^(a+)$/.exec(“aaaaaaaaaaaaaaaaaaaaaaaaaaaX”);
    一个加号倒是很快。。

  13. cjj
    cjj September 28, 2009

    呵呵 好的正则 才能让正则有好的性能

  14. 深空
    深空 September 27, 2009

    没看明白要匹配什么?应该也是尽可能多的匹配a,但是因为最后一个是X,所以打印出null,厄,直接写a+不就行了,在PHP里很快,呵呵。

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.