邵珠庆の日记 生命只有一次,你可以用它来做很多伟大的事情–Make the world a little better and easier


2011月/13

《肖申克的救赎》的几点启示

发布在 邵珠庆

信念

没有信念,什么事情都做不好,因为小小的一个困难就能将你击退。Andy的信念是自由,正是带着这个强烈的信念,才能因为一颗刻字时掉了的石头,联想到越狱,并且实践。花十多年的时间去挖一条隧道,这简直是不可想像的,一旦被发现后果也将非常严重。随便找个理由,都能说服自己不继续这项危险的行为,此时唯有信念才能支撑着Andy继续挖下去。

无论何时都不要放弃希望

Andy及同一批的囚犯到达肖申克时,海利就当场打爆了一个人的头,在这样的环境下,还能有所作为吗?还能对自由抱有幻想吗?Andy用实际行动做了最好的解答:新建图书馆,替狱友考取学历,最后拿着一大笔钱来到了梦想中的地方。

Red说: 希望是危险的东西,是精神苦闷的根源。Andy说: 记住,希望是好事——甚至也许是人间至善。而美好的事永不消失。

规划自己的人生路线

如果Andy只是通过自己挖的洞越狱,那么他很可能会被再次通缉,然后再次进入肖申克。显然Andy考虑到了,他需要一笔钱和一个合法的身份。钱可以从典狱长那里来,而人则可以通过写信写出来。如果把一大笔钱放在一个银行又很容易被怀疑,所以要分散到多家银行,又因为要到银行去取钱,所以需要一身体面的着装(典狱长友情提供)… Andy在之前就已经考虑到了后面的路要怎么走。

精通一门对大家都有用的技能(尤其是当权者)

大家都需要Andy,因为他精通理财,给大家带来了实实在在的好处。正因为这个他才得以得到警卫的庇护,逃离鸡奸狂的魔爪。于是有了为典狱长洗钱的机会,而这个机会对Andy来说是至关重要的。于是他可以新建图书馆,帮狱友考取学历,只要是不太过分的事,基本都能做到。

友谊

Andy与几位狱友有着纯洁的友谊,因为相互之间没有利害关系,尤其是和Red,两人都比较内敛,但心心相应。相比之下,我们的友情则不那么纯粹,经不起时间的考验。尽管大团圆的结局看了很多,但当他们最终在海滩边拥抱时,还是为这份友情而感动。

不抱怨

这是一个被束缚的空间,有着不讲理甚至残暴的当权者,一切都受约束。在这里,有太多可以抱怨的,但是Andy没有,他学会了接受现实,学会了新的游戏规则,在这个规则下,依然可以有希望,有信念,有建树。这点对于我们尤为重要。

坚持

在成功学里,这个词被使用过无数次,也被证明过无数次。Andy用了6年的时间来写信申请图书馆的经费,终于在第6年收到了每年$200的回报和一大堆捐的书/唱片等等。他居然说: it only take 6 years! 那个通向自由的洞,也是在坚持了将近20年后才通的。

1511月/13

web安全扫描工具

发布在 邵珠庆

扫描程序可以在帮助造我们造就安全的Web 站点上助一臂之力,也就是说在黑客“黑”你之前,

先测试一下自己系统中的漏洞。我们在此推荐10大Web 漏洞扫描程序,供您参考。

1. Nikto  http://www.xdowns.com/soft/184/Linux/2012/Soft_99498.html

以下是引用片段:
这是一个开源的Web 服务器扫描程序,它可以对Web 服务器的多种项目(包括3500个潜在的危险
文件/CGI,以及超过900 个服务器版本,还有250 多个服务器上的版本特定问题)进行全面的测
试。其扫描项目和插件经常更新并且可以自动更新(如果需要的话)。
Nikto 可以在尽可能短的周期内测试你的Web 服务器,这在其日志文件中相当明显。不过,如果
你想试验一下(或者测试你的IDS系统),它也可以支持LibWhisker 的反IDS方法。
不过,并非每一次检查都可以找出一个安全问题,虽然多数情况下是这样的。有一些项目是仅提
供信息(“info only” )类型的检查,这种检查可以查找一些并不存在安全漏洞的项目,不过
Web 管理员或安全工程师们并不知道。这些项目通常都可以恰当地标记出来。为我们省去不少麻
烦。 

2. Paros proxy  http://www.xdowns.com/soft/8/19/2012/Soft_99499.html 

以下是引用片段:
这是一个对Web 应用程序的漏洞进行评估的代理程序,即一个基于Java 的web 代理程序,可以
评估Web 应用程序的漏洞。它支持动态地编辑/查看HTTP/HTTPS,从而改变cookies和表单字段
等项目。它包括一个Web 通信记录程序,Web 圈套程序(spider),hash 计算器,还有一个可以
测试常见的Web 应用程序攻击(如SQL 注入式攻击和跨站脚本攻击)的扫描器。

  

3. WebScarab   http://www.xdowns.com/soft/8/19/2012/Soft_99500.html

以下是引用片段:
它可以分析使用HTTP 和HTTPS 协议进行通信的应用程序,WebScarab 可以用最简单地形式记录
它观察的会话,并允许操作人员以各种方式观查会话。如果你需要观察一个基于HTTP(S)应用程
序的运行状态,那么WebScarabi 就可以满足你这种需要。不管是帮助开发人员调试其它方面的
难题,还是允许安全专业人员识别漏洞,它都是一款不错的工具。 

4. WebInspect  http://www.xdowns.com/soft/8/19/2012/Soft_99501.html 

以下是引用片段:
这是一款强大的Web 应用程序扫描程序。SPI Dynamics 的这款应用程序安全评估工具有助于确
认Web 应用中已知的和未知的漏洞。它还可以检查一个Web 服务器是否正确配置,并会尝试一些
常见的Web 攻击,如参数注入、跨站脚本、目录遍历攻击(directory traversal)等等。

  

5. Whisker/libwhisker   http://www.xdowns.com/soft/184/Linux/2012/Soft_99502.html 

以下是引用片段:
Libwhisker 是一个Perla 模块,适合于HTTP 测试。它可以针对许多已知的安全漏洞,测试HTTP
服务器,特别是检测危险CGI 的存在。Whisker 是一个使用libwhisker 的扫描程序。 

6. Burpsuite   http://www.xdowns.com/soft/8/19/2012/Soft_99503.html 

以下是引用片段:
这是一个可以用于攻击Web 应用程序的集成平台。Burp 套件允许一个攻击者将人工的和自动的
技术结合起来,以列举、分析、攻击Web 应用程序,或利用这些程序的漏洞。各种各样的burp
工具协同工作,共享信息,并允许将一种工具发现的漏洞形成另外一种工具的基础。 

7. Wikto   http://www.xdowns.com/soft/8/19/2012/Soft_99504.html 

以下是引用片段:
可以说这是一个Web 服务器评估工具,它可以检查Web 服务器中的漏洞,并提供与Nikto 一样的
很多功能,但增加了许多有趣的功能部分,如后端miner 和紧密的Google 集成。它为MS.NET
环境编写,但用户需要注册才能下载其二进制文件和源代码。 

8. Acunetix Web Vulnerability Scanner  http://www.xdowns.com/soft/8/19/2008/Soft_46786.html 

以下是引用片段:
这是一款商业级的Web 漏洞扫描程序,它可以检查Web 应用程序中的漏洞,如SQL 注入、跨站脚
本攻击、身份验证页上的弱口令长度等。它拥有一个操作方便的图形用户界面,并且能够创建专
业级的Web 站点安全审核报告。

  

9. Watchfire AppScan     http://www.xdowns.com/soft/8/19/2012/Soft_99505.html

以下是引用片段:
这也是一款商业类的Web 漏洞扫描程序。AppScan 在应用程序的整个开发周期都提供安全测试,
从而测试简化了部件测试和开发早期的安全保证。它可以扫描许多常见的漏洞,如跨站脚本攻击、
HTTP 响应拆分漏洞、参数篡改、隐式字段处理、后门/调试选项、缓冲区溢出等等。 

10. N-Stealth   http://www.xdowns.com/soft/8/19/2012/Soft_99509.html 

以下是引用片段:
N-Stealth 是一款商业级的Web 服务器安全扫描程序。它比一些免费的Web 扫描程序,如
Whisker/libwhisker、Nikto 等的升级频率更高,它宣称含有“30000个漏洞和漏洞程序”以及
 “每天增加大量的漏洞检查”,不过这种说法令人质疑。还要注意,实际上所有通用的VA 工具,
如Nessus, ISS Internet Scanner, Retina, SAINT, Sara 等都包含Web 扫描部件。(虽然这些
工具并非总能保持软件更新,也不一定很灵活。)N-Stealth 主要为Windows 平台提供扫描,但
并不提供源代码。 

--------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------
 

商业产品*国外
     ·Acunetix Web Vulnerability Scanner 6 :简称WVS,还是不错的扫描工具,不知道检查
的太细致还是因为慢,总之经常评估一个网站的时候一晚上不关电脑都扫描不万……但是报
表做的不错。一般用这个扫描的话,不用等那么久,像区县政府的,扫20 分钟就差不多了。

     ·IBM   Rational  AppScan:这个是IBM 旗下的产品,扫描速度中规中矩,报表功能相当
强大,可以按照法规遵从生成不同的报表,如:ISO27001、OWASP 等,界面也很商业化。

     ·HP  WebInspect:没错,的确就是卖PC 的HP 公司旗下的产品,扫描速度比上面的2
个都快得多,东西还算不错。不过这几天在和NOSEC                     (下面说的“诺赛科技”)掐架,愣是
说NOSEC 的iiScan 免费扫描平台侵犯隐私,说NOSEC 有国家背景……这市场了解的!

     ·N-Stealth:没装成功,不过很多地方在推荐这个

     ·Burp Suite:貌似是《黑客攻防技术宝典·WEB 实战篇》作者公司搞的,安全界牛人。
虽然工具没用过,但是这本书的确是不错……如果您做WEB 安全,游侠强烈建议您读一下。

商业产品*国内

     ·智恒联盟WebPecker      网站啄木鸟:程序做的不错,扫描速度很快。

     ·诺赛科技Pangolin、Jsky :Pangolin 做SQL 注入扫描,Jsky  全面评估,就是上文说的
NOSEC,网上扫描平台是iiScan,后台的牛人是zwell。

     ·安域领创WebRavor:记得流光(FluXay)否?是的,WebRavor 就是小榕所写!小榕
是谁?搜下……不用我介绍了吧?

     ·安恒MatriXay   明鉴WEB 应用弱点扫描器:还没用过,和NOSEC 一样,也有网上扫
描平台。

绿盟NSFOCUS RSAS    极光远程安全评估系统:极光扫描系统新增的WEB 安全评估插
件,在某客户处见到过扫描报告,不过没用过产品。依照绿盟的一贯风格和绿盟的实力,应
该不错。

免费产品

     ·Nikto:很多地方都在推荐,但游侠本人实在不喜欢命令行产品……各位喜欢的Google
或Baidu 下吧

     ·Paros Proxy:基于Java 搞的扫描工具,速度也挺快,在淘宝QA 团队博客也看到在介
绍这个软件。

     ·WebScarab:传说中很NB 的OWASP 出的产品,不过我看下载地址的时候貌似更新挺

     ·Sandcat:扫描速度很快,检查的项目也挺多。机子现在就装了这个。
    ————

     ·NBSI:应该说是黑客工具更靠谱,国内最早的,可能也是地球上最早的一批SQL 注入
及后续工作利用工具,当年是黑站挂马必备……

     ·HDSI:教主所写,支持ASP 和PHP 注入,功能就不多说了,也是杀人越货必备!

     ·Domain:批量扫描的必备产品,通过whois              扫描服务器上的服务器,在很长一段时
间内风靡黑客圈。
    ————

     ·Nessus:当然它有商业版,不过我们常用的是免费版。脆弱性评估工具,更擅长于主
机、服务器、网络设备扫描。

     ·NMAP:主要倾向于端口等的评估。

     ·X-Scan:安全焦点出品,多少年过去了,依然是很强悍的产品。大成天下曾经做过商
业版的“游刃”,但最近已经不更新了,很可惜。

    其实能做评估的工具还有很多,如:

     ·Retina Network Security Scanner

     ·LANguard Network Security Scanner

榕基RJ-iTop 网络隐患扫描系统

    不过和Nessus 和NMAP 一样,主要倾向于主机安全评估,而不是WEB 应用安全评估。
但我们在WEB  安全评估的时候,不可避免的要对服务器做安全扫描,因此也是必然要用的
工具。

    好了,大体的也说了下,各位感兴趣的可以在网上找下相关资料或下载。看完感觉有点
收获的,就转发给您的朋友吧。

1411月/13

程序员,你还酷吗?–Limboy | 无网不剩

发布在 邵珠庆

当别人问起你的职业,是否会有一丝卑微感,是不是更希望自己的头衔是经理、总监、主管之类的?

面对琳琅满目且不断调整的需求,是否会以完成需求为目的,而不顾程序本身的优雅?

是否觉得程序员就是吃青春饭的,迟早得转型到管理,不如趁早转,积累点经验?

是否觉得自己做的事情很重要,但做成后被褒奖的却不是你,或者只是顺带一提?

看到满屏的英文文档,或遇到搞不定的Bug时,开始怀疑人生?

与女孩子接触的机会太少,真希望调到XX组?

是否觉得与其他人交流起来会有点困难?

是否讨厌办公室政治,又不得不在其中涡旋?

面对不断更新的技术,是否有种无力感?

是否也希望某天能做出一个NB的应用,改变世界?

是否会有扁项目经理的冲动?

如果你对上面提到的这些深有同感,那么作为一个程序员,你可能真的不够酷。程序(app)能够以其独有的方式改善人们的生活,而程序员是触发这一切的根本。他们坐在电脑前,噼里啪啦敲一些外人根本看不懂的符号,熟练地使用快捷键,变魔术般的做好了一个网站/应用,然后你打开电脑/手机就能看到并使用他们,这难道还不够酷吗?

要让人们对某一行业的态度发生转变,最好的方式就是从事该行业的人自己去证明。如果越来越多的程序员创造出了能够改善人们生活方方面面的应用,而且程序员不是简单地去实现,而是以主导者的身份出现,那时候人们对程序员的认识一定会比现在好不少。这就需要程序员不光要会写程序,还要具备创业家的心态,这并没有想像中的那么难,连那么复杂的程序都能搞定,还有什么是自己搞不定的?

在使用一个应用时,如果界面很漂亮,我们会感叹:设计师真NB;如果体验很好,我们会感叹:产品经理真NB;如果程序出了点Bug,我们会抱怨:程序员弱爆了。一个应用正常运行,是程序员应该做的;如果出了问题,自觉修Bug去吧。一个应用,如果真有用户对程序本身赞叹不绝,很可能是UI/UE很不咋地,但程序运行地还挺符合预期。

程序员要得到外界的认可是比较难的,虽然他们在做着很重要的事情。但如果我们真的享受编程带来的乐趣,坚信程序可以让人们的生活变得更加方便和美好,又何必在意外人的看法呢?在属于自己的世界里,静静地绽放,就像深海的水母一样。

最后,千万别惹程序员,因为他们会顺手拿起封面是犀牛的O’Reilly书砸你。

 

http://blog.leezhong.com/essay/2012/07/19/hey-programmers-are-you-cool.html

1411月/13

职业规划是不靠谱的

发布在 邵珠庆

经常会在各种场合听到人们问起:你的职业规划是什么?有些人很快就能给出答案,有些人临时想了一个,有些人则坦然没有想好。

职业规划到底是个什么东西?以程序员来说,架构师、技术总监、CTO等等看起来很风光的Title都会是不错的候选,让自己看起来很有抱负的样子。

可这一点用都没有!甚至还有负作用!假如每天怀揣着成为架构师的目标去工作去学习,我敢保证,不出一个礼拜就会被这个目标拖垮,因为这实在是没有什么激励作用,是扎扎实实的负反馈。感觉今天学到了不少东西,可是一看架构师要懂那么多,那么深,就会觉得自己的这些收获好渺小。

或许你会说,这是大目标,会拆分成很多的小目标。这个理论没有错,但实现上会有不少问题。因为这是一个探索的过程,就好像一个从来没出过远门的南方人,在没有地图的情况下要走到北方的某个城市去。只是知道大概的方向,这种情况下如何设置小目标呢?即使有了地图,能不能把小目标设置地合理也是很大地挑战。这也是为什么有专门的「关卡设计师」这个职位。如果小目标设置得不合理,要么产生挫败感,要么觉得没挑战,这两种情绪对于长远地目标来说都是很不利的。

我们需要的是「浸入式」的体验,这个词对于游戏设计师是很重要的。为什么有些游戏我们能玩上上百关,还乐此不疲?不是因为在最开始的时候,告诉自己「我一定要玩到100关!」,而是渐进的难度设置让你在每一关完成后都有成就感。在玩第19关时,你断然不会想「真好,离100关又进了1步」。

游戏和生活很多地方是相通的。为什么有些人从事了某项职业10年还不如别人3年成就更高,道理也一样。因为在玩到某一关后,他停止了向难度更大的下一关迈进,反复玩着同一关,自然不会有进步。所以用「工龄」去判断一个人的能力是很容易失误的。

我们希望自己变得强大,这没有问题。希望自己变得像XXX一样,这也没有问题,有希望总是好的嘛。但如果把XXX(高级Title)作为自己的职业目标,就有些问题了。你不一定知道怎样才能成为XXX,也就是说没有一条明确的道路,即使有,也未必适合你,即使你已做好了充分的准备,也难保在行进的过程中不受其他事物的诱惑,或者发现自己并不喜欢这条路。很可能你只是看到了XXX光鲜的一面,然后天真地以为自己只要努力也一定能做到,直到被现实虐得体无完肤。

每一行都不容易,这是很简单就可以推导出来的,假设确实有那么几个行业很容易,也很挣钱,除非正好被你赶上了,不然人一多,门槛自然也就上去了。

费曼老师说过:每一件事情都可以很有意思。认清自己的现状,发现自己的不足,享受解决问题的乐趣,在不断的正反馈下慢慢地去拓宽自己的知识圈,增强解决问题的能力。如果有了这种元能力,在每一行都能做得很好,很快乐。

1311月/13

《将博客搬至CSDN》 2013-11-13 13:56 225人阅读 评论(0) 收藏

发布在 邵珠庆

(为了确认是您本人在申请搬家,请在原博客发表一 篇标题为《将博客搬至CSDN》的文章,

并将文章地址填写在上方的"搬家通知博文地址"中。)

1211月/13

PHP中Push(推送)技术的探讨

发布在 邵珠庆

随着人们对Web即时应用需求的不断上升,Server Push(推送)技术在聊天、消息提醒尤其是社交网络等方面开始兴起,成为实时应用的数据流核心。这篇日志试图探讨的便是各种适合于PHP的Push的实现方式以及其优劣。

1. 什么是Server Push

想象在聊天应用中,如果使用传统的ajax来承担消息的传入,那么一般是通过每隔一定时间拉取一次信息的方式实现,但是其实这种方式有大量查询是浪费的。聊天等Web应用更需要服务器在特定时间来主动告知前端有新的消息(Push),而不是前端每时每刻问服务器:“来消息了吗?”(Pull)。这也正是为什么这个技术常被叫做反向ajax。

其他别名:Comet,反向Ajax

 

2. 如何实现Push

其实所谓的推送技术也没有多么复杂,目前从大类上有3种,一种仍然建立在ajax基础上,还有一种建立在框架基础上,最后一种抛弃了传统的HTTP协议,使用Flash或者HTML5的WebSockets技术。接下来将对这三种类别产生的不同的方式进行探讨。

 

1) Ajax 长轮询

Ajax长轮询从本质上来说仍然是一种pull,但是实时性较高,无用请求减少很多,是一种不错的Push实现方案。不过它只减少了网络上的无谓消耗。

核心: 客户端发起一个ajax请求,服务端将请求搁置(pending)或者说挂起,直到到了超时时间(timeout)或需要推送时返回;客户端则等待ajax返回后处理数据,再发起下一个ajax请求。

优点: 兼容性较高,实现简单

缺点: 对于php这种语言来说,如果要做到实时,那么服务端就要承受大得多的压力,因为搁置到什么时候往往是不确定的,这就要php脚本每次搁置都进行一个while循环。
当然,如果服务器刷新每秒级,那尚可接受,只是实时性上退化了。

注意: 浏览器有连接数限制。我得出的结论是如果当前页面上有一个ajax请求处于等待返回状态,那么其他ajax请求都会被搁置(Chrome, Firefox已测)。似乎跟页面标记有关,一个规范的HTML可以同时有多个请求。如果页面有一般ajax需求怎么办?解决方法是开个框架,框架中使在另一个域名下进行Comet长轮询,需要注意跨域问题。

PHP实现: Jquery+php实现comet

相关: Ajax跨域和js跨域解决方案

 

2) Frame 长连接

受到ajax启发,出现了框架下的长连接。

核心: Frame中发起一个普通请求,服务器将其搁置;需要推送时输出直接执行
脚本,然后继续保持连接。如果担心超时问题可以改成框架论询。

优点: 与1一样具有高兼容特性

缺点: 最大的问题是如果框架在载入,那么浏览器就好一直显示“载入中”,这就弱爆了(解决方法参见文末的相关阅读资源)。同样服务器也要能hold住大量循环……另外,是否有同域连接限制没测试。

 

3) Flash/HTML5 WebSockets

用flash来发起WebSockets,秒杀前面一切问题。

优点: 标准化, RealTime, Push

缺点: 服务器需要能应对WebSockets;还有如果既没有Flash又不支持HTML5的怎么办?

PHP实现: Start Using HTML5 WebSockets Today

 

6) 使用兼容封装层(socket.io)

以上每种方法都有优劣,那么终极解决方案便是合在一起!能WebSockets时候就WebSockets,不支持HTML5特性就退化到Flash,没有Flash则退化到Ajax长轮询。这也是我的Rainbowfish所采用的方式。

优点: 高度封装,编写非常容易,几乎不需要关心如何去实现的。实时,超低负载,高并发。

缺点: 其实算不上缺点,socket.io的服务器端要求是node.js,而不是php。

个人看法: 如果你是独立主机,能运行程序,那么socket.io配合node.js是个非常高效的选择。为什么呢?因为它还可以避免php的服务端高负载。

Rainbowfish的消息系统通过这种方式实现: 所有客户端都通过socket.io挂在nodejs服务器上(注意: 只是挂着,不需要任何循环,因为它是事件驱动的);需要推送消息了,服务器就与nodejs通信(比如访问某个地址来实现),告诉它推送什么消息到哪里;nodejs收到推送信号后,则通过socket.io实时传输数据给浏览器。这个其实也是一条单向的路,因为nodejs服务器不具备与php通信的能力,实际上也不需要,网页上直接连php就可以了。

 

3. 结束语

事实上,第一个方法(Ajax Long Pull)是一个不错的方法,只是如果使用php完成的话服务器负载上有点大,但这其实是通病;而最后列举的socket.io方案完全避免了这个问题,因为它属于另一种架构,并且这种组合也可以配合几乎所有的脚本语言实现push。

对于实时性要求非常高的应用,或许使用php实现实时部分并不是一个好的选择,将会面临非常大的服务器负载(可以通过编写支持等待事件的扩展来解决这个问题);如果只是消息提示等,则可以调整服务器上刷新的间隔降低到秒的级别,负载尚可接受。不过无论哪种用途,配合那些非阻塞语言或许才是最好的选择。

 

4. 相关阅读

How to implement COMET with PHP

Start Using HTML5 WebSockets Today

Comet(Wikipedia)

Ajax跨域和js跨域解决方案

Jquery+php实现comet

811月/13

谷歌Web界面和搜索语言代码

发布在 邵珠庆

谷歌Web界面和搜索语言代码

本文包含谷歌Web界面语言列表
验证码(hl=)和搜索语言代码(lr=) ,可以被插入
Web浏览器时,在地址栏的URL (网页地址)
使用谷歌的服务,如果你的问题,请
与谷歌的语言设置。在那里的那一刻( 2012年6月)
149 Web界面语言代码和46个搜索语言代码。该
已收集到的HTML源代码的谷歌语言代码
首选项页面,你可以找到他们从那里还可以。此页面
主要的目的是列出的语言代码,这样你就可以复制
您正在使用的URL的字符(例如HL = EN或LR = lang_en )
但你也可以直接到您的首选语言界面
通过点击相应的链接在一个网页或搜索语言页
下面的两个列表。

记住,不是所有的谷歌服务已被翻译成
下面列出的所有语言。此外,增加后的语言代码
任何的URL不会起作用,所以你可能需要做一些试验
找出你可以将它们添加。

用法示例
例如,如果您使用的是谷歌网页搜索页面和URL
在您的网页浏览器的地址栏中:

   http://www.google.com/search ?

您可以定义web界面语言是英语,加入
HL = EN结尾的网址,变更后的网址看起来
像这样:

   http://www.google.com/search?hl=en

当你使用一个以上的设置代码,你需要在URL中使用
与他们之间的字符。例如,如果你也想定义
搜索语言是英语,你需要使用&字符
像这样的代码之间:

   http://www.google.com/search?hl=en&lr=lang_en

因为上面的URL可能不会工作,使选定的搜索
语言将被使用,如果你尝试在该网页上做一个搜索,你也
需要添加一个搜索查询的URL (Q =) ,所以产生的URL
是:

   http://www.google.com/search?hl=en&lr=lang_en&q=example

记住按后键盘上的回车键(或等效键)
添加了所需的字符。

Web界面语言代码
hl=af          Afrikaans
hl=ak          Akan
hl=sq          Albanian
hl=am          Amharic
hl=ar          Arabic
hl=hy          Armenian
hl=az          Azerbaijani
hl=eu          Basque
hl=be          Belarusian
hl=bem         Bemba
hl=bn          Bengali
hl=bh          Bihari
hl=xx-bork     Bork, bork, bork!
hl=bs          Bosnian
hl=br          Breton
hl=bg          Bulgarian
hl=km          Cambodian
hl=ca          Catalan
hl=chr         Cherokee
hl=ny          Chichewa
hl=zh-CN       Chinese (Simplified)
hl=zh-TW       Chinese (Traditional)
hl=co          Corsican
hl=hr          Croatian
hl=cs          Czech
hl=da          Danish
hl=nl          Dutch
hl=xx-elmer    Elmer Fudd
hl=en          English
hl=eo          Esperanto
hl=et          Estonian
hl=ee          Ewe
hl=fo          Faroese
hl=tl          Filipino
hl=fi          Finnish
hl=fr          French
hl=fy          Frisian
hl=gaa         Ga
hl=gl          Galician
hl=ka          Georgian
hl=de          German
hl=el          Greek
hl=gn          Guarani
hl=gu          Gujarati
hl=xx-hacker   Hacker
hl=ht          Haitian Creole
hl=ha          Hausa
hl=haw         Hawaiian
hl=iw          Hebrew
hl=hi          Hindi
hl=hu          Hungarian
hl=is          Icelandic
hl=ig          Igbo
hl=id          Indonesian
hl=ia          Interlingua
hl=ga          Irish
hl=it          Italian
hl=ja          Japanese
hl=jw          Javanese
hl=kn          Kannada
hl=kk          Kazakh
hl=rw          Kinyarwanda
hl=rn          Kirundi
hl=xx-klingon  Klingon
hl=kg          Kongo
hl=ko          Korean
hl=kri         Krio (Sierra Leone)
hl=ku          Kurdish
hl=ckb         Kurdish (Soranî)
hl=ky          Kyrgyz
hl=lo          Laothian
hl=la          Latin
hl=lv          Latvian
hl=ln          Lingala
hl=lt          Lithuanian
hl=loz         Lozi
hl=lg          Luganda
hl=ach         Luo
hl=mk          Macedonian
hl=mg          Malagasy
hl=ms          Malay
hl=ml          Malayalam
hl=mt          Maltese
hl=mi          Maori
hl=mr          Marathi
hl=mfe         Mauritian Creole
hl=mo          Moldavian
hl=mn          Mongolian
hl=sr-ME       Montenegrin
hl=ne          Nepali
hl=pcm         Nigerian Pidgin
hl=nso         Northern Sotho
hl=no          Norwegian
hl=nn          Norwegian (Nynorsk)
hl=oc          Occitan
hl=or          Oriya
hl=om          Oromo
hl=ps          Pashto
hl=fa          Persian
hl=xx-pirate   Pirate
hl=pl          Polish
hl=pt-BR       Portuguese (Brazil)
hl=pt-PT       Portuguese (Portugal)
hl=pa          Punjabi
hl=qu          Quechua
hl=ro          Romanian
hl=rm          Romansh
hl=nyn         Runyakitara
hl=ru          Russian
hl=gd          Scots Gaelic
hl=sr          Serbian
hl=sh          Serbo-Croatian
hl=st          Sesotho
hl=tn          Setswana
hl=crs         Seychellois Creole
hl=sn          Shona
hl=sd          Sindhi
hl=si          Sinhalese
hl=sk          Slovak
hl=sl          Slovenian
hl=so          Somali
hl=es          Spanish
hl=es-419      Spanish (Latin American)
hl=su          Sundanese
hl=sw          Swahili
hl=sv          Swedish
hl=tg          Tajik
hl=ta          Tamil
hl=tt          Tatar
hl=te          Telugu
hl=th          Thai
hl=ti          Tigrinya
hl=to          Tonga
hl=lua         Tshiluba
hl=tum         Tumbuka
hl=tr          Turkish
hl=tk          Turkmen
hl=tw          Twi
hl=ug          Uighur
hl=uk          Ukrainian
hl=ur          Urdu
hl=uz          Uzbek
hl=vi          Vietnamese
hl=cy          Welsh
hl=wo          Wolof
hl=xh          Xhosa
hl=yi          Yiddish
hl=yo          Yoruba
hl=zu          Zulu

搜索语言代码
lr=lang_af    Afrikaans
lr=lang_ar    Arabic
lr=lang_hy    Armenian
lr=lang_be    Belarusian
lr=lang_bg    Bulgarian
lr=lang_ca    Catalan
lr=lang_zh-CN Chinese (Simplified)
lr=lang_zh-TW Chinese (Traditional)
lr=lang_hr    Croatian
lr=lang_cs    Czech
lr=lang_da    Danish
lr=lang_nl    Dutch
lr=lang_en    English
lr=lang_eo    Esperanto
lr=lang_et    Estonian
lr=lang_tl    Filipino
lr=lang_fi    Finnish
lr=lang_fr    French
lr=lang_de    German
lr=lang_el    Greek
lr=lang_iw    Hebrew
lr=lang_hi    Hindi
lr=lang_hu    Hungarian
lr=lang_is    Icelandic
lr=lang_id    Indonesian
lr=lang_it    Italian
lr=lang_ja    Japanese
lr=lang_ko    Korean
lr=lang_lv    Latvian
lr=lang_lt    Lithuanian
lr=lang_no    Norwegian
lr=lang_fa    Persian
lr=lang_pl    Polish
lr=lang_pt    Portuguese
lr=lang_ro    Romanian
lr=lang_ru    Russian
lr=lang_sr    Serbian
lr=lang_sk    Slovak
lr=lang_sl    Slovenian
lr=lang_es    Spanish
lr=lang_sw    Swahili
lr=lang_sv    Swedish
lr=lang_th    Thai
lr=lang_tr    Turkish
lr=lang_uk    Ukrainian
lr=lang_vi    Vietnamese


简短的文字只有语言代码一览表

af, ach, ak, am, ar, az, be, bem, bg, bh, bn, br, bs, ca, chr, ckb, 
co, crs, cs, cy, da, de, ee, el, en, eo, es, es-419, et, eu, fa, fi, 
fo, fr, fy, ga, gaa, gd, gl, gn, gu, ha, haw, hi, hr, ht, hu, hy, ia, 
id, ig, is, it, iw, ja, jw, ka, kg, kk, km, kn, ko, kri, ku, ky, la, 
lg, ln, lo, loz, lt, lua, lv, mfe, mg, mi, mk, ml, mn, mo, mr, ms, mt,
ne, nl, nn, no, nso, ny, nyn, oc, om, or, pa, pcm, pl, ps, pt-BR, 
pt-PT, qu, rm, rn, ro, ru, rw, sd, sh, si, sk, sl, sn, so, sq, sr, 
sr-ME, st, su, sv, sw, ta, te, tg, th, ti, tk, tl, tn, to, tr, tt, 
tum, tw, ug, uk, ur, uz, vi, wo, xh, xx-bork, xx-elmer, xx-hacker, 
xx-klingon, xx-pirate, yi, yo, zh-CN, zh-TW, zu.
链接

相关网页

谷歌翻译
谷歌音译
谷歌在你的语言
谷歌翻译工具
谷歌翻译博客


新闻

现在谷歌搜索支持切诺基(2011年3月)
现在我们听! ( 2010年12月)
屏幕上的键盘谷歌翻译(2010年12月)
在香港(2010年12月,谷歌推出广东话语音搜寻)
音译走向全球(2009年12月)
51语言在Google翻译(2009年8月)
 
版权所有(C) 2007-2014 :shaozhuqing( shaozhuqing.com )。

 
免责声明:本文提供不带任何明示或
暗示的保证。虽然已采取一切努力,以确保
本文中包含的信息的准确度的
贡献者的错误或遗漏,或不承担任何责任
从使用的信息造成的损害所载。


最后编辑时间: 2012年6月11日
整理:邵珠庆( shaozhuqing.com )
网址: http://shaozhuqing.com/?p=2769
411月/13

Iframe高度自适应(兼容IE/Firefox、同域/跨域)

发布在 邵珠庆

在实际的项目进行中,很多地方可能由于历史原因不得不去使用iframe,包括目前正火热的应用开发也是如此。

随之而来的就是在实际使用iframe中,会遇到iframe高度的问题,由于被嵌套的页面长度不固定而显示出来的滚动条,不仅影响美观,还会对用户操作带来不便。于是自动调整iframe的高度就成为本文的重点。

采用JavaScript来控制iframe元素的高度是iframe高度自适应的关键,同时由于JavaScript对不同域名下权限的控制,引发出同域、跨域两种情况。

同域时Iframe高度自适应
下面的代码兼容IE/Firefox浏览器,控制id为“iframeid”的iframe的高度,通过JavaScript取得被嵌套页面最终高度,然后在主页面进行设置来实现。

代码如下,可复制。另外,请注意此解决方案仅供同域名下使用。

<script type="text/javascript">
 function SetCwinHeight(){
  var iframeid=document.getElementById("iframeid"); //iframe id
  if (document.getElementById){
   if (iframeid && !window.opera){
    if (iframeid.contentDocument && iframeid.contentDocument.body.offsetHeight){
     iframeid.height = iframeid.contentDocument.body.offsetHeight;
    }else if(iframeid.Document && iframeid.Document.body.scrollHeight){
     iframeid.height = iframeid.Document.body.scrollHeight;
    }
   }
  }
 }
</script>
<iframe width="100%" id="iframeid" onload="Javascript:SetCwinHeight()" height="1" frameborder="0" src="kimi.php"></iframe>

跨域时Iframe高度自适应
在主页面和被嵌套的iframe为不同域名的时候,就稍微麻烦一些,需要避开JavaScript的跨域限制。

原理:现有iframe主页面main.html、被iframe嵌套页面iframe.html、iframe中介页面agent.html三个,通过main.html(域名为http://www.ccvita.com)嵌套iframe.html(域名为:http://www.phpq.net),当用户浏览时执行iframe.html中的JavaScript代码设置iframeC的scr地址中加入iframe页面的高度,agent.html(域名为:http://www.ccvita.com)取得传递的高度,通过JavaScript设置main.html中iframe的高度。最终实现预期的目标。

演示地址:http://www.ccvita.com/usr/uploads/demo/iframe/main.html
代码下载:http://www.ccvita.com/usr/uploads/demo/iframe/iframe.zip

 

iframe主页面main.html

< !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>iframe主页面</title></head>
<body>
 
<div style="border:1px solid #ccc;padding:10px;"><iframe id="frame_content"  name="frame_content" src="iframe.html" width="100%" height="0" scrolling="no" frameborder="0"></iframe></div><br />尾部<br /></body>
</html>

iframe嵌套页面iframe.html

< !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>被iframe嵌套页面</title></head>
<body>
 
文字<br /><br /><br /><br /><br /><br /><br /><br /><br /><br />文字<br /><br /><br /><br /><br /><br /><br /><br /><br /><br />文字<br /><br /><br /><br /><br /><br /><br /><br /><br /><br />文字<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><iframe id="iframeC" name="iframeC" src="" width="0" height="0" style="display:none;" ></iframe>
 
<script type="text/javascript">
function sethash(){
    hashH = document.documentElement.scrollHeight;
    urlC = "agent.html";
    document.getElementById("iframeC").src=urlC+"#"+hashH;
}
window.onload=sethash;
</script>
 
</body>
</html>

iframe中介页面agent.html

< !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>iframe中介页面</title></head>
 
<body>
 
<script>
function  pseth() {
    var iObj = parent.parent.document.getElementById('frame_content');
    iObjH = parent.parent.frames["frame_content"].frames["iframeC"].location.hash;
    iObj.style.height = iObjH.split("#")[1]+"px";
}
pseth();
</script>
 
</body>
</html>

UPDATE:长期以来一直有网友说方案不能跨域,今天我重新又测试了下,确定在IE6、IE7、IE8、IE9、Firefox全系列、Chrome全系列均可以成功跨域控制高度。请注意以下要点

  • 第一,修改main.html文件中iframe的src地址为需要跨域的域名(比如ccvita.sinaapp.com)
  • 第二,修改iframe.html文件中的urlC值为源域名(比如www.ccvita.com)这点最重要
411月/13

iframe同域或异域下高度自动适应(兼容种浏览器)

发布在 邵珠庆

利用javascript来控制iframe的高度自动适应,介于javascript对不同域名权限的限制,分为两种情况:

同域名情况下:

同域名下面,iframe自动适应高度,相对简单,下面代码兼容所有浏览器

  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  2. <html xmlns="http://www.w3.org/1999/xhtml">
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5. <title>iframe自动适应高度</title>
  6. <script type="text/javascript">
  7. <!--//
  8. function sizeFrame() {
  9.     var F = document.getElementById("myFrame");
  10.     if(F.contentDocument) {
  11.         F.height = F.contentDocument.documentElement.scrollHeight; //FF 3.0.11, Opera 9.63, and Chrome
  12.     } else {
  13.         F.height = F.contentWindow.document.body.scrollHeight; //IE6, IE7 and Chrome
  14.     }
  15. }
  16. window.onload=sizeFrame;
  17. //-->
  18. </script>
  19. </head>
  20. <body>
  21. <iframe width="100%" id="myFrame" src="http://www.a.com" scrolling="no" frameborder="0">同域情况</iframe>
  22. </body>
  23. </html>

异域情况下:

假设有一个main.html页面在服务器A上,有一个待载入的页面test.html在服务器B上。要想实现main.html利用iframe载入test.html,iframe高度要实现自动延伸,可利用一个中介页面z.html

方法:

B服务器上的页面test.html利用隐藏iframe加载z.html,test.html页面计算自己的页面高度并赋值给z.html的hash即 z.html#height(计算出的高度),z.html加载时,获取hash,并设置main.html中iframe的高度。废话不说了,直接看下面的代码吧

main.html

  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  2. <html xmlns="http://www.w3.org/1999/xhtml">
  3. <head>
  4. <script type="text/javascript">
  5. <!--//
  6. function sizeFrame() {
  7.     var F = document.getElementById("iframeB");
  8.     if(F.contentDocument) {
  9.         F.height = F.contentDocument.documentElement.scrollHeight; //FF 3.0.11, Opera 9.63, and Chrome
  10.     } else {
  11.         F.height = F.contentWindow.document.body.scrollHeight; //IE6, IE7 and Chrome
  12.     }
  13. }
  14. window.onload=sizeFrame;
  15. //-->
  16. </script>
  17. </head>
  18. <body>
  19. <iframe id="iframeB"  name="iframeB" src="http://www.b.com/test.html" width="100%" height="auto" scrolling="no" frameborder="0"></iframe>
  20. </body>
  21. </html>
  22.  

test.html页面中需要加入的代码如下

  1. <iframe id="iframeA" name="iframeA" src="" width="0" height="0" style="display:none;" ></iframe>
  2. <script type="text/javascript">
  3. function sethash(){
  4.     hashH = document.documentElement.scrollHeight; //获取自身高度
  5.     urlC = "http://www.a.com/z.html"; //设置iframeA的src
  6.     document.getElementById("iframeA").src=urlC+"#"+hashH; //将高度作为参数传递
  7. }
  8. window.onload=sethash;
  9. </script>

中介页面z.html代码:

  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  2. <html xmlns="http://www.w3.org/1999/xhtml">
  3. <head>
  4. <script type="text/javascript">
  5. function  pseth() {
  6.     var iObj = parent.parent.document.getElementById('iframeB');//A和main同域,所以可以访问节点
  7.     iObjH = parent.parent.frames["iframeB"].frames["iframeA"].location.hash;//访问自己的location对象获取hash值
  8.     iObj.style.height = iObjH.split("#")[1]+"px";//操作dom
  9. }
  10. pseth();
  11. </script>
  12. </head>
  13. <body>
  14. </body>
  15. </html>

查看demo

 
411月/13

浅析JavaScript执行顺序

发布在 邵珠庆

JavaScript执行顺序

之前从JavaScript引擎的解析机制来探索JavaScript的工作原理,下面我们以更形象的示例来说明JavaScript代码在页面中的执行顺序。如果说,JavaScript引擎的工作机制比较深奥是因为它属于底层行为,那么JavaScript代码执行顺序就比较形象了,因为我们可以直观感觉到这种执行顺序,当然JavaScript代码的执行顺序是比较复杂的,所以在深入JavaScript语言之前也有必要对其进行剖析。

1.1  按HTML文档流顺序执行JavaScript代码

首先,读者应该清楚,HTML文档在浏览器中的解析过程是这样的:浏览器是按着文档流从上到下逐步解析页面结构和信息的。JavaScript代码作为嵌入的脚本应该也算做HTML文档的组成部分,所以JavaScript代码在装载时的执行顺序也是根据脚本标签<script>的出现顺序来确定的。例如,浏览下面文档页面,你会看到代码是从上到下逐步被解析的。

<script>

alert("顶部脚本");

</script>

<html><head>

<script>

alert("头部脚本");

</script>

<title></title>

</head>

<body>

<script>

alert("页面脚本");

</script>

</body></html>

<script>

alert("底部脚本");

</script>

如果通过脚本标签<script>的src属性导入外部JavaScript文件脚本,那么它也将按照其语句出现的顺序来执行,而且执行过程是文档装载的一部分。不会因为是外部JavaScript文件而延期执行。例如,把上面文档中的头部和主体区域的脚本移到外部JavaScript文件中,然后通过src属性导入。继续预览页面文档,你会看到相同的执行顺序。

<script>

alert("顶部脚本");

</script>

<html>

<head>

<script src="head.js"></script>

<title></title>

</head>

<body>

<script src="body.js"></script>

</body>

</html>

<script>

alert("底部脚本");

</script>

1.2  预编译与执行顺序的关系

在Javascript中,function才是Javascript的第一型。当我们写下一段函数时,其实不过是建立了一个function类型的实体。

就像我们可以写成这样的形式一样:

functionHello() {

alert("Hello");

}

Hello();

varHello = function() {

alert("Hello");

}

Hello();

其实都是一样的。

但是当我们对其中的函数进行修改时,会发现很奇怪的问题。

   <scripttype="text/javascript">

        functionHello() {

            alert("Hello");

        }

        Hello();

        functionHello() {

            alert("Hello World");

        }

        Hello();

    </script>

我们会看到这样的结果:连续输出了两次Hello World。而非我们想象中的Hello和Hello World。

这是因为Javascript并非完全的按顺序解释执行,而是在解释之前会对Javascript进行一次“预编译”,在预编译的过程中,会把定义式的函数优先执行,也会把所有var变量创建,默认值为undefined,以提高程序的执行效率。也就是说上面的一段代码其实被JS引擎预编译为这样的形式:

    <scripttype="text/javascript">

        varHello = function() {

            alert("Hello");

        }

        Hello = function() {

            alert("Hello World");

        }

        Hello();

        Hello();

    </script>

我们可以通过上面的代码很清晰地看到,其实函数也是数据,也是变量,我们也可以对“函数“进行赋值(重赋值)。当然,我们为了防止这样的情况,也可以这样:

 <scripttype="text/javascript">

        functionHello() {

            alert("Hello");

        }

        Hello();

    </script>

    <scripttype="text/javascript">

        functionHello() {

            alert("Hello World");

        }

        Hello();

    </script>

这样,程序被分成了两段,JS引擎也就不会把他们放到一起了。

 

 

当JavaScript引擎解析脚本时,它会在预编译期对所有声明的变量和函数进行处理。

做如下处理:

1. 在执行前会进行类似“预编译”的操作:首先会创建一个当前执行环境下的活动对象,并将那些用var申明的变量设置为活动对象的属性,但是此时这些变量的赋值都是undefined,并将那些以function定义的函数也添加为活动对象的属性,而且它们的值正是函数的定义。

2. 在解释执行阶段,遇到变量需要解析时,会首先从当前执行环境的活动对象中查找,如果没有找到而且该执行环境的拥有者有prototype属性时则会从prototype链中查找,否则将会按照作用域链查找。遇到var a = ...这样的语句时会给相应的变量进行赋值(注意:变量的赋值是在解释执行阶段完成的,如果在这之前使用变量,它的值会是undefined)
所以,就会出现当JavaScript解释器执行下面脚本时不会报错:

alert(a);                            // 返回值undefined

var a =1;

alert(a);                            // 返回值1

由于变量声明是在预编译期被处理的,所以在执行期间对于所有代码来说,都是可见的。但是,你也会看到,执行上面代码,提示的值是undefined,而不是1。这是因为,变量初始化过程发生在执行期,而不是预编译期。在执行期,JavaScript解释器是按着代码先后顺序进行解析的,如果在前面代码行中没有为变量赋值,则JavaScript解释器会使用默认值undefined。由于在第二行中为变量a赋值了,所以在第三行代码中会提示变量a的值为1,而不是undefined。

同理,下面示例在函数声明前调用函数也是合法的,并能够被正确解析,所以返回值为1。

f();                                 // 调用函数,返回值1

function f(){

    alert(1);

}

但是,如果按下面方式定义函数,则JavaScript解释器会提示语法错误。

f();                                 // 调用函数,返回语法错误

var f = function(){

    alert(1);

}

这是因为,上面示例中定义的函数仅作为值赋值给变量f,所以在预编译期,JavaScript解释器只能够为声明变量f进行处理,而对于变量f的值,只能等到执行期时按顺序进行赋值,自然就会出现语法错误,提示找不到对象f。

再见一些例子:

 

<script type="text/javascript">

/*在预编译过程中func是window环境下的活动对象中的一个属性,值是一个函数,覆盖了undefined值*/

alert(func); //function func(){alert("hello!")}

var func = "this is a variable"

function func(){

alert("hello!")

}

/*在执行过程中遇到了var重新赋值为"this is a variable"*/

alert(func);  //this is a variable

</script>

 

<script type="text/javascript">
var name = "feng";
function func(){
/*首先,在func环境内先把name赋值为undefined,然后在执行过程中先寻找func环境下的活动对象的name属性,此时之前已经预编译值为undefined,所以输出是undefined,而不是feng*/
alert(name);  //undefined
var name = "JSF";
alert(name);  //JSF
}
func();
alert(name); //feng
</script>

虽然变量和函数声明可以在文档任意位置,但是良好的习惯应该是在所有JavaScript代码之前声明全局变量和函数,并对变量进行初始化赋值。在函数内部也是先声明变量,然后再引用。

 

1.3  按块执行JavaScript代码

所谓代码块就是使用<script>标签分隔的代码段。例如,下面两个<script>标签分别代表两个JavaScript代码块。

<script>

// JavaScript代码块1

var a =1;

</script>

<script>

// JavaScript代码块2

function f(){

    alert(1);

}

</script>

JavaScript解释器在执行脚本时,是按块来执行的。通俗地说,就是浏览器在解析HTML文档流时,如果遇到一个<script>标签,则JavaScript解释器会等到这个代码块都加载完后,先对代码块进行预编译,然后再执行。执行完毕后,浏览器会继续解析下面的HTML文档流,同时JavaScript解释器也准备好处理下一个代码块。

由于JavaScript是按块执行的,所以如果在一个JavaScript块中调用后面块中声明的变量或函数就会提示语法错误。例如,当JavaScript解释器执行下面代码时就会提示语法错误,显示变量a未定义,对象f找不到。

<script>

// JavaScript代码块1

alert(a);

f();

</script>

<script>

// JavaScript代码块2

var a =1;

function f(){

    alert(1);

}

</script>

虽然说,JavaScript是按块执行的,但是不同块都属于同一个全局作用域,也就是说,块之间的变量和函数是可以共享的。

1.4  借助事件机制改变JavaScript执行顺序

由于JavaScript是按块处理代码,同时又遵循HTML文档流的解析顺序,所以在上面示例中会看到这样的语法错误。但是当文档流加载完毕,如果再次访问就不会出现这样的错误。例如,把访问第2块代码中的变量和函数的代码放在页面初始化事件函数中,就不会出现语法错误了。

<script>

// JavaScript代码块1

window.onload = function(){        // 页面初始化事件处理函数

    alert(a);

    f();

}

</script>

<script>

// JavaScript代码块2

var a =1;

function f(){

    alert(1);

}

</script>

为了安全起见,我们一般在页面初始化完毕之后才允许JavaScript代码执行,这样可以避免网速对JavaScript执行的影响,同时也避开了HTML文档流对于JavaScript执行的限制。

注意

如果在一个页面中存在多个windows.onload事件处理函数,则只有最后一个才是有效的,为了解决这个问题,可以把所有脚本或调用函数都放在同一个onload事件处理函数中,例如:

window.onload = function(){

    f1();

    f2();

    f3();

}

而且通过这种方式可以改变函数的执行顺序,方法是:简单地调整onload事件处理函数中调用函数的排列顺序。

除了页面初始化事件外,我们还可以通过各种交互事件来改变JavaScript代码的执行顺序,如鼠标事件、键盘事件及时钟触发器等方法,详细讲解请参阅第14章的内容。

1.5  JavaScript输出脚本的执行顺序

在JavaScript开发中,经常会使用document对象的write()方法输出JavaScript脚本。那么这些动态输出的脚本是如何执行的呢?例如:

document.write('<script type="text/javascript">');

document.write('f();');

document.write('function f(){');

document.write('alert(1);');

document.write('}');

document.write('</script>');

运行上面代码,我们会发现:document.write()方法先把输出的脚本字符串写入到脚本所在的文档位置,浏览器在解析完document.write()所在文档内容后,继续解析document.write()输出的内容,然后才按顺序解析后面的HTML文档。也就是说,JavaScript脚本输出的代码字符串会在输出后马上被执行。

请注意,使用document.write()方法输出的JavaScript脚本字符串必须放在同时被输出的<script>标签中,否则JavaScript解释器因为不能够识别这些合法的JavaScript代码,而作为普通的字符串显示在页面文档中。例如,下面的代码就会把JavaScript代码显示出来,而不是执行它。

document.write('f();');

document.write('function f(){');

document.write('alert(1);');

document.write(');');

但是,通过document.write()方法输出脚本并执行也存在一定的风险,因为不同JavaScript引擎对其执行顺序不同,同时不同浏览器在解析时也会出现Bug。

Ø 问题一,找不到通过document.write()方法导入的外部JavaScript文件中声明的变量或函数。例如,看下面示例代码。

document.write('<script type="text/javascript" src="test.js">

</script>');

document.write('<script type="text/javascript">');

document.write('alert(n);');  // IE提示找不到变量n

document.write('</script>');

alert(n+1);                          // 所有浏览器都会提示找不到变量n

外部JavaScript文件(test.js)的代码如下:

var n = 1;

分别在不同浏览器中进行测试,会发现提示语法错误,找不到变量n。也就是说,如果在JavaScript代码块中访问本代码块中使用document.write()方法输出的脚本中导入的外部JavaScript文件所包含的变量,会显示语法错误。同时,如果在IE浏览器中,不仅在脚本中,而且在输出的脚本中也会提示找不到输出的导入外部JavaScript文件的变量(表述有点长和绕,不懂的读者可以尝试运行上面代码即可明白)。

Ø 问题二,不同JavaScript引擎对输出的外部导入脚本的执行顺序略有不同。例如,看下面示例代码。

<script type="text/javascript">

document.write('<script type="text/javascript" src="test1.js">

</script>');

document.write('<script type="text/javascript">');

document.write('alert(2);')

document.write('alert(n+2);');

document.write('</script>');

</script>

<script type="text/javascript">

alert(n+3);

</script>

外部JavaScript文件(test1.js)的代码如下所示。

var n = 1;

alert(n);

在IE浏览器中的执行顺序如图1-6所示。

 

图1-6  IE 7浏览器的执行顺序和提示的语法错误

在符合DOM标准的浏览器中的执行顺序与IE浏览器不同,且没有语法错误,如图1-7所示的是在Firefox 3.0浏览器中的执行顺序。

 

图1-7  Firefox 3浏览器的执行顺序和提示的语法错误

解决不同浏览器存在的不同执行顺序,以及可能存在Bug。我们可以把凡是使用输出脚本导入的外部文件,都放在独立的代码块中,这样根据上面介绍的JavaScript代码块执行顺序,就可以避免这个问题。例如,针对上面示例,可以这样设计:

<script type="text/javascript">

document.write('<script type="text/javascript" src="test1.js"></script>');

</script>

<script type="text/javascript">

document.write('<script type="text/javascript">');

document.write('alert(2);') ; // 提示2

document.write('alert(n+2);'); // 提示3

document.write('</script>');

alert(n+3); // 提示4

</script>

<script type="text/javascript">

alert(n+4); // 提示5

</script>

这样在不同浏览器中都能够按顺序执行上面代码,且输出顺序都是1、2、3、4和5。存在问题的原因是:输出导入的脚本与当前JavaScript代码块之间的矛盾。如果单独输出就不会发生冲突了。