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


123月/150

Console命令详解,让调试js代码变得更简单

发布在 邵珠庆


控制台(Console)是Firebug的第一个面板,也是最重要的面板,主要作用是显示网页加载过程中产生各类信息。

一、显示信息的命令

Firebug内置一个console对象,提供5种方法,用来显示信息。

最简单的方法是console.log(),可以用来取代alert()或document.write()。比如,在网页脚本中使用console.log("Hello World"),加载时控制台就会自动显示如下内容。

另外,根据信息的不同性质,console对象还有4种显示信息的方法,分别是一般信息console.info()、除错信息console.debug()、警告提示console.warn()、错误提示console.error()。

比如,在网页脚本中插入下面四行:

  console.info("这是info");

console.debug("这是debug");

console.warn("这是warn");

console.error("这是error");

加载时,控制台会显示如下内容。

可以看到,不同性质的信息前面有不同的图标,并且每条信息后面都有超级链接,点击后跳转到网页源码的相应行。

二、占位符

console对象的上面5种方法,都可以使用printf风格的占位符。不过,占位符的种类比较少,只支持字符(%s)、整数(%d或%i)、浮点数(%f)和对象(%o)四种。

比如,

  console.log("%d年%d月%d日",2011,3,26);

console.log("圆周率是%f",3.1415926);

%o占位符,可以用来查看一个对象内部情况。比如,有这样一个对象:

  var dog = {} ;

dog.name = "大毛" ;

dog.color = "黄色";

然后,对它使用o%占位符。

  console.log("%o",dog);

三、分组显示

如果信息太多,可以分组显示,用到的方法是console.group()和console.groupEnd()。

  console.group("第一组信息");

console.log("第一组第一条");

console.log("第一组第二条");

console.groupEnd();

console.group("第二组信息");

console.log("第二组第一条");

console.log("第二组第二条");

console.groupEnd();

点击组标题,该组信息会折叠或展开。

四、console.dir()

console.dir()可以显示一个对象所有的属性和方法。

比如,现在为第二节的dog对象,添加一个bark()方法。

  dog.bark = function(){alert("汪汪汪");};

然后,显示该对象的内容,

  console.dir(dog);

五、console.dirxml()

console.dirxml()用来显示网页的某个节点(node)所包含的html/xml代码。

比如,先获取一个表格节点,

  var table = document.getElementById("table1");

然后,显示该节点包含的代码。

  console.dirxml(table);

六、console.assert()

console.assert()用来判断一个表达式或变量是否为真。如果结果为否,则在控制台输出一条相应信息,并且抛出一个异常。

比如,下面两个判断的结果都为否。

  var result = 0;

console.assert( result );

var year = 2000;

console.assert(year == 2011 );

七、console.trace()

console.trace()用来追踪函数的调用轨迹。

比如,有一个加法器函数。

  function add(a,b){

return a+b;

}

我想知道这个函数是如何被调用的,在其中加入console.trace()方法就可以了。

  function add(a,b){

console.trace();

return a+b;

}

假定这个函数的调用代码如下:

  var x = add3(1,1);

function add3(a,b){return add2(a,b);}

function add2(a,b){return add1(a,b);}

function add1(a,b){return add(a,b);}

运行后,会显示add()的调用轨迹,从上到下依次为add()、add1()、add2()、add3()。

八、计时功能

console.time()和console.timeEnd(),用来显示代码的运行时间。

  console.time("计时器一");

for(var i=0;i<1000;i++){

for(var j=0;j<1000;j++){}

}

console.timeEnd("计时器一");

九、性能分析

性能分析(Profiler)就是分析程序各个部分的运行时间,找出瓶颈所在,使用的方法是console.profile()。

假定有一个函数Foo(),里面调用了另外两个函数funcA()和funcB(),其中funcA()调用10次,funcB()调用1次。

  function Foo(){

for(var i=0;i<10;i++){funcA(1000);}

funcB(10000);

}

function funcA(count){

for(var i=0;i<count;i++){}

}

function funcB(count){

for(var i=0;i<count;i++){}

}

然后,就可以分析Foo()的运行性能了。

  console.profile('性能分析器一');

Foo();

console.profileEnd();

控制台会显示一张性能分析表,如下图。

标题栏提示,一共运行了12个函数,共耗时2.656毫秒。其中funcA()运行10次,耗时1.391毫秒,最短运行时间0.123毫秒,最长0.284毫秒,平均0.139毫秒;funcB()运行1次,耗时1.229ms毫秒。

除了使用console.profile()方法,firebug还提供了一个"概况"(Profiler)按钮。第一次点击该按钮,"性能分析" 开始,你可以对网页进行某种操作(比如ajax操作),然后第二次点击该按钮,"性能分析"结束,该操作引发的所有运算就会进行性能分析。

十、属性菜单

控制台面板的名称后面,有一个倒三角,点击后会显示属性菜单。

默认情况下,控制台只显示Javascript错误。如果选中Javascript警告、CSS错误、XML错误都送上,则相关的提示信息都会显示。

这里比较有用的是"显示XMLHttpRequests",也就是显示ajax请求。选中以后,网页的所有ajax请求,都会在控制台面板显示出来。

比如,点击一个YUI示例,控制台就会告诉我们,它用ajax方式发出了一个GET请求,http请求和响应的头信息和内容主体,也都可以看到。

271月/150

Code Review 同行代码审查实战分析

发布在 邵珠庆

代码审查(Code Review)是软件开发中常用的手段,和QA测试相比,它更容易发现较难发现的问题,还可以帮助团队成员提高编程技能,统一编程风格等。本文作者从实际出发,详细分析了开发者在代码审查过程中会遇到的问题及解决方法。

以下为译文:

数百万年前,人类祖先人猿学会直立行走——解放双手——最终进化到人;而代码审查在开发过程中有着异曲同工之妙——区别出野蛮开发和先进开发。

然而,在实际工作中,以下声音总不绝于耳:

  1. “代码审查在项目中简直就是浪费时间!”
  2. “我根本没有时间去做复查。”
  3. “由于我那个谨慎的拍档还没做好复查,进度只能延后了。”
  4. “你确定,我的同事要求我修改代码吗?请向他们解释一下,任何轻微地改动都会让我的代码失去原有的优雅。”

那么问题来了,我们为什么需要做代码复查?

作为专业的软件开发人员,持续提高代码质量是工作生涯不断追求的目标之一。无论我们有多么优秀,都离不开团队;而代码复查是个人与团队的润滑剂:

  • 当局者迷,旁观者清。代码复查如同为我们安装了后视镜;
  • 使我们的代码多了至少一个知音人;
  • 能帮助新员工在这个过程中学习和领悟到前辈的代码精髓;
  • 有助开展知识共享,众“智”成城。

要做就要做到最好

如果想要达成上述种种美好结果,是离不开时间和工作的科学安排的。仅仅做好代码缩进、变量命名规范等基本工作,还不能算得上完美。而如果曾经尝试过结对编程,或许你会发现其所花的时间往往都比代码复查要多。

我的建议是用开长总时长的四分之一时间来进行代码复查。举例来说,如果开发总用时为两天,那么应该花上大约四个小时来进行复查。

当然,如果能把事情做对,可不必拘泥于时间的多少。进一步说,我们必须能看明白将要复查的代码。这不仅代表要掌握基本的语言语法,更关键的是要掌握整个代码的架构,所用组件或库等细节。如果不能做到对每一行代码所做的事情都了然于胸,这样的复查工作是没有多少价值的。所以要做好这点是不能一味讲求速度的,必须花一番功夫来从头到尾对代码进行梳理分析。

此外还有两件事是务必要做到的:

  1. 复查工作中包含所有必须的测试工作;
  2. 做好设计文档的编写工作。

避免拖延症

今天的工作今天完成是最完美的工作状态,否则一旦拖延症出现,再多再好的复查都只会成为开发过程中的绊脚石。好的复查需要紧密而持久的努力,不是搞搞突击就能做好的。

因此,开发者应当尽力做到日清日结。把复查作为每天工作的开端是个不错的主意;理清旧的思路将有助于开展新的编码任务。也或许有的人喜欢在午休或下班前进行,无论在什么时候进行,以下几点是应该避免的:

  • 让积压工作越积越多;
  • 由于复查没有做好而导致进度延后;
  • 由于代码更新频率快就放弃做复查;
  • 往往在最后一刻才去做复查。

编写出可复查的代码

不应该把所有复查工作都推给复查员。如果我的同事花了一周时间添加了看起来比较乱的代码,这对复查工作无疑是重大打击,也很难让人摸清其思路和结构。

所以我们在编程时,要有意识地把代码划分为可操作单元。我们使用的方法是scrum,它为我们的开发工作做了很明晰的指导,同时使得整个开发过程有迹可循,便于进行追溯和回顾。

其次,在与复查员进行讨论前要搞好关系。这样将有助于双方对彼此有所了解,从而减少讨论时矛盾发生的机率。

再者,项目结构应当在设计文档中描述得清楚具体。这对于项目新成员的成长是大有裨益的,同时能帮助复查员提高工作效率。

最后也是最重要的一点是在自我复查过程中做好注释。换言之要先自行对代码过一遍,把需要做出说明的地方标示出来并解释清楚。有研究表明,开发者在对自己的进行复查和注释时,经常会找出不少瑕疵。

大型代码重构

有时候如果需要进行代码重构,这势必会影响到很多组件,特别是较大型的应用。在这种情况下,最好的解决方案是逐步推进重构工作。先对要做的变更进行划分,然后根据修改意图进行分段式重构。当这部分变更完成并做好复查后,再执行第二部分的重构,重复该步骤直至完成全部工作。这或许增加了重构用时,但会带来更高质量的代码同时可以减轻复查员的工作量。

如果实际情况真的不允许进行逐步重构,可以试试结对编程。

解决矛盾

在一个技术团队中,各人有各自的观点,如何达成共识是成败的关键。作为开发者,应该保持开明的心态并虚心接受不同的意见。避免固步自封,避免对自我复查工作的不屑一顾。如果有人提议把我们一些重复的代码做成一个可复用函数,这并不代表我们之前的工作是毫无价值的。

而作为复查员,要懂得人情世故。在给出修改意见前,先考虑清楚这真的会更好抑或仅仅是风格上的不同看法。提议说法可以是:“如果尝试另一种方法,或许会更好”或“有同事建议这样做”,而要避免的是:“就连我家宠物都能写出比这好的算法!”

如果真的一时僵持不下,争议双方不妨请教第三个开发人员,从他的角度来再次审度各自的观点,直到形成共识,三人行,必有我师焉。

107月/140

开发者的10个最佳代码游乐场

发布在 邵珠庆

如果你是开发者,在寻找最佳的代码游乐场,享受代码的乐趣,那么你来到了正确的地方。在这篇文章中我已经收集了用于测试、调试和分享代码的10个最好的免费代码游乐场(Code Playground)和沙盒工具。如果你知道其他好的代码游乐场,可以通过评论告诉我。Enjoy!

1. Codepen

 CodePen是一个web前后端游乐场。它基于激发、传授和分享。能高亮热门示例(“Pen”),且提供高级功能,如共享和嵌入。需要建立一个减少测试案例来演示并找出一个bug?CodePen绝对适合这个场景。想炫耀你的最新创作和获得同行的反馈? CodePen是绝一不二的选择。

2. CSSDesk

CSSDesk是一个在线CSS沙箱。它使人们能够快速测试的CSS代码片段,并观察实时结果。我有非常看好这个项目。有行号和文本框输入实时语法高亮显示。其中一个最好的一点是它允许用户与他人分享他们的代码。

3. Google’s Code Playground

 谷歌的代码游乐场是一个基于Web的工具,可以让Web开发人员尝试谷歌所有提供的API,调整代码,和查看结果。谷歌的代码游乐场可以让您尽情享受而不必打开一个外部编辑器,所有的API都被装载在(左侧)“Pick an API”框中。

4. JS Bin

JS Bin是一个web app,专门设计于帮助JavaScript和CSS亲们在某些上下文中测试和协作调试代码。 JS Bin允许你编辑和测试JavaScript和HTML。一旦满意,你可以保存并发送这URL给同行审查或寻求帮助。然后,他们可以做更进一步的修改,如果需要保存更新。

5. JSFiddle

JSFiddle中是一个shell编辑器,通过创建基于流行JS框架的自定义环境,简化JavaScript的编写。你可以选择框架和版本(可选的有MooTools,jQuery,ojo, Prototype, YUI, Glow,Vanilla)。此外,如果行的话,你可以添加jQuery UI或MooTools More之类的免费框架。它具有一个极好的特征是能够产生一个唯一的URL以保存和分享代码。另外,JSFiddle也自带嵌入特征。它是无需网站就可尝试和分享JS代码的极佳平台。

6. Dabblet

 Dabblet是快速测试CSS和HTML代码片段的交互式游乐场。它使用-prefix-free,不必在你的CSS代码添加任何前缀。可以在Github gist保存工作内容,将其嵌入到其他网站和与他人分享。它目前只支持Chrome,Safari和Firefox的现代版本。所有发布的代码属于发布者,没有强制许可证。 Dabblet本身是开源软件,在NPOSL-3.0许可下发布。

7. Editr

Editr是一个集HTML,CSS和JavaScript的游乐场,你可以在自己的服务器上托管。它是基于ACE的编辑器。它的超级容易安装。它支持一个页面多个实例。可以通过JS对象或HTML属性进行配置。 Editr支持3种视觉布局:水平,垂直和单一。前两个是用于在线编辑。第三个是用于演示。 Editr基于MIT License。

8. Livewave

 Liveweave是用于HTML5、CSS3、JavaScript的游乐场和用于网页设计师和开发者实时编辑器。这是用来测试,练习和分享成果的好工具!面板大小可调,可以让你随心所欲写(或织,如我们称呼它名字一样)代码。 Liveweave还内置了对HTML5和CSS3的标签/属性上下文敏感的代码提示,使生活变得更加简单。

9. D3 Playground

D3.js设计目的在于让你能够以交互方式使用D3.js库。每一次编辑(产生有效代码)都会实时影响D3.js游乐场。因为CSS是可视化的重要组成部分,你也可以在线编辑CSS。

10. HTML5 Playground

 HTML5的游乐场包括一个可以看HTML5动作的代码库。它们包括一些基础启动例程,如HTML5 Doctype和音频标记(仍然是兼容浏览器中回放特性的好demo)。拥有一个交互表格,包含HTML5元素,如范围、日期输入和针对电子邮件地址和网站的自动验证。

155月/140

升级Universal Analytics部署代码

发布在 邵珠庆

https://developers.google.com/analytics/devguides/collection/analyticsjs/advanced
 
<!-- Google Analytics -->
<script>
/**
 * Creates a temporary global ga object and loads analy  tics.js.
 * Paramenters o, a, and m are all used internally.  They could have been declared using 'var',
 * instead they are declared as parameters to save 4 bytes ('var ').
 *
 * @param {Window}      i The global context object.
 * @param {Document}    s The DOM document object.
 * @param {string}      o Must be 'script'.
 * @param {string}      g URL of the analytics.js script. Inherits protocol from page.
 * @param {string}      r Global name of analytics object.  Defaults to 'ga'.
 * @param {DOMElement?} a Async script tag.
 * @param {DOMElement?} m First script tag in document.
 */
(function(i, s, o, g, r, a, m){
  i['GoogleAnalyticsObject'] = r; // Acts as a pointer to support renaming.

  // Creates an initial ga() function.  The queued commands will be executed once analytics.js loads.
  i[r] = i[r] || function() {
    (i[r].q = i[r].q || []).push(arguments)
  },

  // Sets the time (as an integer) this tag was executed.  Used for timing hits.
  i[r].l = 1 * new Date();

  // Insert the script tag asynchronously.  Inserts above current tag to prevent blocking in
  // addition to using the async attribute.
  a = s.createElement(o),
  m = s.getElementsByTagName(o)[0];
  a.async = 1;
  a.src = g;
  m.parentNode.insertBefore(a, m)
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');

ga('create', 'UA-XXXX-Y', 'auto'); // Creates the tracker with default parameters.
ga('send', 'pageview');            // Sends a pageview hit.
</script>
<!-- End Google Analytics -->
811月/130

谷歌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
246月/130

HTML/CSS/Javascript代码在线压缩、格式化(美化)工具

发布在 邵珠庆

CSS 格式化ProCSSor - http://procssor.com/

CSS 压缩CSS Compressor - http://www.cssdrive.com/index.php/main/csscompressor

HTML 格式化Tabifier - http://tools.arantius.com/tabifier

HTML 压缩Compress HTML - http://www.textfixer.com/html/compress-html-compression.php

Javascript 格式化Online javascript beautifier - http://jsbeautifier.org/

Javascript 压缩Closure Compiler - http://closure-compiler.appspot.com/

代码高亮Quick Highlighter - http://quickhighlighter.com/

273月/130

编写可读代码的艺术

发布在 邵珠庆

代码为什么要易于理解

“Code should be written to minimize the time it would take for someone else to understand it.”

日常工作的事实是:

  • 写代码前的思考和看代码的时间远大于真正写的时间
  • 读代码是很平常的事情,不论是别人的,还是自己的,半年前写的可认为是别人的代码
  • 代码可读性高,很快就可以理解程序的逻辑,进入工作状态
  • 行数少的代码不一定就容易理解
  • 代码的可读性与程序的效率、架构、易于测试一点也不冲突

整本书都围绕“如何让代码的可读性更高”这个目标来写。这也是好代码的重要标准之一。

如何命名

变量名中应包含更多信息

使用含义明确的词,比如用download而不是get,参考以下替换方案:

1
2
3
4
send -> deliver, dispatch, announce, distribute, route
 find -> search, extract, locate, recover
start -> lanuch, create, begin, open
 make -> create,set up, build, generate, compose, add, new

避免通用的词

tmpretval这样词,除了说明是临时变量和返回值之外,没有任何意义。但是给他加一些有意义的词,就会很明确:

1
2
3
tmp_file = tempfile.NamedTemporaryFile()
...
SaveData(tmp_file, ...)

不使用retval而使用变量真正代表的意义:

1
sum_squares += v[i]; // Where's the "square" that we're summing? Bug!

嵌套的for循环中,ij也有同样让人困惑的时候:

1
2
3
4
for (int i = 0; i < clubs.size(); i++)
 for (int j = 0; j < clubs[i].members.size(); j++)
 for (int k = 0; k < users.size(); k++) if (clubs[i].members[k] == users[j])
 cout << "user[" << j << "] is in club[" << i << "]" << endl;

换一种写法就会清晰很多:

1
if (clubs[ci].members[mi] == users[ui]) # OK. First letters match.

所以,当使用一些通用的词,要有充分的理由才可以。

使用具体的名字

CanListenOnPort就比ServerCanStart好,can start比较含糊,而listen on port确切的说明了这个方法将要做什么。

--run_locally就不如--extra_logging来的明确。

增加重要的细节,比如变量的单位_ms,对原始字符串加_raw

如果一个变量很重要,那么在名字上多加一些额外的字就会更加易读,比如将string id; // Example: "af84ef845cd8"换成string hex_id;

1
2
3
4
Start(int delay) --> delay → delay_secs
 CreateCache(int size) --> size → size_mb
ThrottleDownload(float limit) --> limit → max_kbps
 Rotate(float angle) --> angle → degrees_cw

更多例子:

1
2
3
4
password -> plaintext_password
 comment -> unescaped_comment
 html -> html_utf8
 data -> data_urlenc

对于作用域大的变量使用较长的名字

在比较小的作用域内,可以使用较短的变量名,在较大的作用域内使用的变量,最好用长一点的名字,编辑器的自动补全都可以很好的减少键盘输入。对于一些缩写前缀,尽量选择众所周知的(如str),一个判断标准是,当新成员加入时,是否可以无需他人帮助而明白前缀代表什么。

合理使用_-等符号,比如对私有变量加_前缀。

1
2
3
4
5
6
7
8
var x = new DatePicker(); // DatePicker() 是类的"构造"函数,大写开始
var y = pageHeight(); // pageHeight() 是一个普通函数
 
var $all_images = $("img"); // $all_images 是jQuery对象
var height = 250; // height不是
 
//id和class的写法分开
<div id="middle_column" class="main-content"> ...

命名不能有歧义

命名的时候可以先想一下,我要用的这个词是否有别的含义。举个例子:

1
results = Database.all_objects.filter("year <= 2011")

现在的结果到底是包含2011年之前的呢还是不包含呢?

使用minmax代替limit

1
2
3
4
5
6
7
CART_TOO_BIG_LIMIT = 10
 if shopping_cart.num_items() >= CART_TOO_BIG_LIMIT:
 Error("Too many items in cart.")
 
MAX_ITEMS_IN_CART = 10
 if shopping_cart.num_items() > MAX_ITEMS_IN_CART:
 Error("Too many items in cart.")

对比上例中CART_TOO_BIG_LIMITMAX_ITEMS_IN_CART,想想哪个更好呢?

使用firstlast来表示闭区间

1
2
3
4
print integer_range(start=2, stop=4)
# Does this print [2,3] or [2,3,4] (or something else)?
 
set.PrintKeys(first="Bart", last="Maggie")

firstlast含义明确,适宜表示闭区间。

使用beiginend表示前闭后开(2,9))区间

1
2
3
PrintEventsInRange("OCT 16 12:00am", "OCT 17 12:00am")
 
PrintEventsInRange("OCT 16 12:00am", "OCT 16 11:59:59.9999pm")

上面一种写法就比下面的舒服多了。

Boolean型变量命名

1
bool read_password = true;

这是一个很危险的命名,到底是需要读取密码呢,还是密码已经被读取呢,不知道,所以这个变量可以使用user_is_authenticated代替。通常,给Boolean型变量添加ishascanshould可以让含义更清晰,比如:

1
2
SpaceLeft() --> hasSpaceLeft()
bool disable_ssl = false --> bool use_ssl = true

符合预期

1
2
3
4
5
6
7
public class StatisticsCollector {
 public void addSample(double x) { ... }
 public double getMean() {
 // Iterate through all samples and return total / num_samples
 }
 ...
}

在这个例子中,getMean方法遍历了所有的样本,返回总额,所以并不是普通意义上轻量的get方法,所以应该取名computeMean比较合适。

漂亮的格式

写出来漂亮的格式,充满美感,读起来自然也会舒服很多,对比下面两个例子:

1
2
3
4
5
6
7
8
9
10
11
12
class StatsKeeper {
 public:
 // A class for keeping track of a series of doubles
 void Add(double d); // and methods for quick statistics about them
 private: int count; /* how many so far
 */ public:
 double Average();
 private: double minimum;
 list<double>
 past_items
 ;double maximum;
};

什么是充满美感的呢:

1
2
3
4
5
6
7
8
9
10
11
12
// A class for keeping track of a series of doubles
// and methods for quick statistics about them.
class StatsKeeper {
 public:
 void Add(double d);
 double Average();
 private:
 list<double> past_items;
 int count; // how many so far
 double minimum;
 double maximum;
};

考虑断行的连续性和简洁

这段代码需要断行,来满足不超过一行80个字符的要求,参数也需要注释说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class PerformanceTester {
 public static final TcpConnectionSimulator wifi = new TcpConnectionSimulator(
 500, /* Kbps */
 80, /* millisecs latency */
 200, /* jitter */
 1 /* packet loss % */);
 
 public static final TcpConnectionSimulator t3_fiber = new TcpConnectionSimulator(
 45000, /* Kbps */
 10, /* millisecs latency */
 0, /* jitter */
 0 /* packet loss % */);
 
 public static final TcpConnectionSimulator cell = new TcpConnectionSimulator(
 100, /* Kbps */
 400, /* millisecs latency */
 250, /* jitter */
 5 /* packet loss % */);
}

考虑到代码的连贯性,先优化成这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class PerformanceTester {
 public static final TcpConnectionSimulator wifi =
 new TcpConnectionSimulator(
 500, /* Kbps */
 80, /* millisecs latency */ 200, /* jitter */
 1 /* packet loss % */);
 
 public static final TcpConnectionSimulator t3_fiber =
 new TcpConnectionSimulator(
 45000, /* Kbps */
 10, /* millisecs latency */
 0, /* jitter */
 0 /* packet loss % */);
 
 public static final TcpConnectionSimulator cell =
 new TcpConnectionSimulator(
 100, /* Kbps */
 400, /* millisecs latency */
 250, /* jitter */
 5 /* packet loss % */);
}

连贯性好一点,但还是太罗嗦,额外占用很多空间:

1
2
3
4
5
6
7
8
9
10
11
12
public class PerformanceTester {
 // TcpConnectionSimulator(throughput, latency, jitter, packet_loss)
 // [Kbps] [ms] [ms] [percent]
 public static final TcpConnectionSimulator wifi =
 new TcpConnectionSimulator(500, 80, 200, 1);
 
 public static final TcpConnectionSimulator t3_fiber =
 new TcpConnectionSimulator(45000, 10, 0, 0);
 
 public static final TcpConnectionSimulator cell =
 new TcpConnectionSimulator(100, 400, 250, 5);
}

用函数封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Turn a partial_name like "Doug Adams" into "Mr. Douglas Adams".
// If not possible, 'error' is filled with an explanation.
string ExpandFullName(DatabaseConnection dc, string partial_name, string* error);
 
DatabaseConnection database_connection;
string error;
assert(ExpandFullName(database_connection, "Doug Adams", &error)
 == "Mr. Douglas Adams");
assert(error == "");
assert(ExpandFullName(database_connection, " Jake Brown ", &error)
 == "Mr. Jacob Brown III");
assert(error == "");
assert(ExpandFullName(database_connection, "No Such Guy", &error) == "");
assert(error == "no match found");
assert(ExpandFullName(database_connection, "John", &error) == "");
assert(error == "more than one result");

上面这段代码看起来很脏乱,很多重复性的东西,可以用函数封装:

1
2
3
4
5
6
7
8
9
10
11