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. JellyZ
    JellyZ April 17, 2017

    学到了

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

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

  3. jonwang
    jonwang May 16, 2012

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

  4. sking7
    sking7 October 20, 2011

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

  5. piapai
    piapai April 17, 2011

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

  6. Cherry
    Cherry October 26, 2009

    你的JS也是如此的牛啊

  7. jindw
    jindw October 16, 2009

    够诡异,够专业。

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

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

  9. toms
    toms October 12, 2009

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

  10. 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都正常运行了的

  11. phppan
    phppan October 1, 2009

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

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

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

  13. yuehei
    yuehei September 28, 2009

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

  14. cjj
    cjj September 28, 2009

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

  15. 深空
    深空 September 27, 2009

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

Comments are closed.