Archive for the ‘javascript’ Category

“我从来不用if-else…”

Saturday, May 1st, 2010

前几天,同事面试完回来哈哈大笑说,面试的人折腾了半天一个简单的程序没有搞定,还很牛逼哄哄地说我写程序从来不用if-else…连Mark同学听到也开心地笑了,呵呵

这几天路上无聊琢磨到底不用if-else怎么写程序,倒是想了几个办法。(使用JavaScript)

方法一:用while代替.

function noifelsewhile(condition){
    while(condition){
	alert("I'm Jack");
	break;
    }
    while(!condition){
	alert("I'm Rose");
	break;
   }
}
noifelsewhile(true);
noifelsewhile(false);

方法二:用for代替.
和while一个套路

function noifelsefor(condition){
   for(;condition;){
	alert("I'm Jack")
	break;
   }
 
   for(;!condition;){
	alert("I'm Rose");
	break;
   }
}
noifelsefor(true);
noifelsefor(false);

办法三:三元表达式
因为三元表达式只能使用表达式,所以需要使用一个function用来支持多行statements

function noifelseternary(condition){
    condition?function(){
		    alert("I'm Jack");
		}():
		function(){
		    alert("I'm Rose");
		}();
}
noifelseternary(true);
noifelseternary(false);

办法四:逻辑与或-Default
在JavaScript中&&是logical and, 也可以称谓guard。如果第一个参数是false,那么返回第一个值,否则返回第二个值。而并不一定返回true或false;

var value = p && p.name; /* The name value will only be retrieved from p if p has a value, avoiding an error. */

||是logical or,也可以成为default。如果第一个参数是false,那么返回第二个值,反则返回第一个只。同样并不是一定返回true或者false。

value = v || 10; /* Use the value of v, but if v doesn't have a value, use 10 instead. */

更多这个信息可以查看A Survey of the JavaScript Programming Language
好,现在就运用这个两个操作来模拟if-else

function noifelsedefault(condition){
 (condition || 
	function(){
		alert("I'm Rose");
	}())&& 
	function(){
		alert("I'm Jack");
	}();
}
noifelsedefault(true);
noifelsedefault(false);

办法五:逻辑与或-Guard
这一次把&&放到前面。这种逻辑与或在其他语言也有,比如python中的and,or

function noifelseguard(condition){
  (condition && 
	function(){
		alert("I'm Jack");
		return true; //注意一定要有return true,要保证这个函数返回true。
                //其实办法4中需要保证第一个函数返回false,因为没有返回值就是null,所以就可以不用显式加return false了。
	}())||
	function(){
		alert("I'm Rose");
	}();
}
noifelseguard(true);
noifelseguard(false);

还有其他的办法吗?大家来变态~,:)
五一快乐~

读《PPK on JavaScript》

Wednesday, July 8th, 2009

PPK也是在JavaScript世界中的风云人物了,这位老兄对于浏览器端的技术以及各种浏览器的兼容性有极其丰富的经验。在这本书中,他谈了很多关于可访问性(Accessibility)和可用性(Usability)的一些问题,非常有趣。比如他说“不同的开发者以不同的方式诠释了JavaScript的目的。简单而形象地说就是:深受CSS革命影响的传统Web开发者们,创建的是瘦的、可访问性很强、乱糟糟的JavaScript代码;而来至服务器端开发的‘资深程序员们’用完美的面向对象代码、创建的是胖的、可访问性很差的Ajax客户端”。显然,ppk同学应该属于写乱糟糟但可访问性很好的人,而现在我做的大量事情却是后者。他更多相信现在的Ajax只是一种泡沫,当这个泡沫破灭并且大量‘资深服务器程序员’消失时,JS的开发者会更加注重可访问性。 可能体会不到ppk经历浏览器各种痛苦的经历,但是总体来说浏览器都在坚定地遵循Web标准,JavaScript的支持也会成为浏览器必备要求。anyway,事情总在发展,好戏在后头。分享一下我觉得这本书中几个有趣的地方。

可访问性和可用性

可访问性(Accessibility)是指你的网页对于任何人、在任何环境下都是可持续访问的。特别是指某些用户,比如弱视、浏览器不支持JavaScript或者另外一些情况,比如用户使用Mobile使用你的网页等等。而可用性(Usability)是指使用或者浏览你的网页的容易程度(这里我们只谈web页面),通常它指我们能更有效率地使用、更容易地学习以及更加满意地使用它。举个例子来说,你让你的web页面支持IE6,或者支持mobile都是在提高它的可访问性;而是用CSS来改善布局让用户更容易阅读、使用JavaScript做一些对用户有帮助的互动都是在提高它的可用性。

Web页面都是由下面三个层组成的,通过它们我们可以了解到它们之间的关系以及它们和可访问性和可用性之间的关系。

  • HTML结构层
  • CSS表现层
  • JavaScript行为层

web3layers

Web页面的三个层,HTML结构层是必需的基础,CSS表现层和JavaScript行为层建于它之上。所以在客户端代码中不得不关注的话题就是这三个层的关注点分离。具体探讨一下这三个的分离:

表现与结构的分离(CSS与HTML)

这个分离很好理解,基本思想就是确保HTML来定义结构,而所有的表现都定义在另外单独的CSS文件中。HTML不应该出现<font>标签和用于表现的表格。如果想定义字体和布局,都应该在CSS中处理。

大部分情况下面我们知道达到某个效果是修改表现或者结构是清楚的。但是有些情况下当更改HTML和修改CSS都可以时,你需要慎重地思考到底哪种是合理的。比如一个节点,你希望它不显示,那么你可以在HTML上面删除该节点或者使用CSS来“display:none”。当这种情况是,需要自己分析所需要的效果属于哪种情况,然后修改合理的层。

行为与结构的分离(JavaScript与HTML)

这个也比较好理解,就是不要把任何的JavaScript代码写到你的HTML页面中。应该把所有JavaScript代码放到一个独立的js文件中,然后将它链入到所有需要它的HTML页面中。

关于这个有一个有趣的话题就是:无侵入脚本编程(unobtrusive scripting).简单来说它就是通过HTML和JavaScript的分离以达到页面的可访问性和可用性的最大化。既JavaScript失效了,页面还是可阅读和理解的;而通过引入脚本和JavaScript的hook,就可以让脚本运行,增强可用性。

行为与表现的分离(JavaScript与CSS)

这个的分离是非常复杂的,而且并没有总结出什么特别系统的规则。CSS和JavaScript是有重合的灰色地带的,有时候完全不能确切地把某个效果归为表现还是行为。比如是使用CSS中的hover还是JavaScript的mouseover/mouseout。基本来说你自己得根据具体情况做合理的选择吧。

事件捕捉模型

在HTML的事件模型中有一个有趣的话题。这个简单的问题就是:如果一个节点和它的父亲节点都有对同一个事件的处理,那么到底哪个事件会被先执行呢?这就是关于事件的冒泡和捕获。事件冒泡是说事件从它的目标元素开始,沿着文档树依次向上冒泡,并触发相应的事件处理函数。而事件的捕捉是刚好相反的,它从文档的第一级开始,然后沿着文档树向下游,知道事件目标为止。

在W3C模型中,捕获和冒泡都会发生。当一个事件触发时,它先被文档捕获,到了事件目标后,再冒泡到文档顶层。而传统模型和微软模型只支持事件冒泡,而不支持事件捕获。所以最好是限制使用事件冒泡。其实在我们的实际编程中,很少关心这个话题,是因为大部分情况我们都只使用了事件冒泡。

更加具体的可以查看ppk的文章:http://www.quirksmode.org/js/events_order.html

小记

应该来说PPK所谈的JavaScript是一个更加全面的浏览器编程的世界,让人可以全面来了解这个世界包含的东西。其实大部分的内容在PPK的网站上都有,值得读读。http://www.quirksmode.org/js/contents.html

Dojo widget的析构过程

Friday, June 5th, 2009

了解dojo widget(或者说dijit)的析构过程,不仅让你更加了解整个dijit的生命周期,同样也能帮助我们在自己定制化的dijit中如何正确地释放资源。(这里讨论的dojo应该是在0.9或者以上版本的)

下面是dijit的析构过程:

                        destroyRecursive
                    /                      \
                destroy                   destroyDescendants
        /        |        \
uninitialize  disconnect() destroyRendering

一些常见的错误是如下:

  • 使用destroy()去销毁一个dijit。我们应该使用destroyRecursive()去销毁一个dijit,从上面的过程可以看出,destroyRecursive()会销毁其孩子widgets。
  • 使用destory()去销毁定制dijit中的资源。更可怕的是有的代码可能是直接覆盖destroy,而根本不调用_Widget中的destory。uninitialize()才是dijit暴露出来给定制化widget进行析构的stub function。

结论

使用destroyRecursive()去销毁dijit,使用uninitialize()在定制化的dijit来释放自己的资源。destroyDescendants,destroyRendering基本上用不到,也不要去覆盖它们。

为什么Firefox 3不能加载本地的JavaScript文件了?

Friday, June 5th, 2009

一段时间来一直受这样的困扰,就是我的Firefox无法运行本地的dojo的测试文件。一直以为是我的firefox或者机器出了什么问题,就只好去使用IE或者Chrome去运行这些测试例子,可惜不能用firebug的确让人很不爽。

今天在firebug查看了一些错误情况,报错居然是“Access to restricted URI denied”。这个明显是跨域访问的错误,但是本地文件怎么报这样的错呢?在Firefox的about:config搜索了一下policy,居然找到了原因所在,原来Firefox对于本地文件也进行了同源访问的安全设置,配置参数是:security.fileuri.strict_origin_policy。这个新的设置只是在firefox 3才被加入,并且默认是开启的。不过你也可以将这个关掉,这样就可以如同以前那样运行本地的dojo测试用例,或者其它你想本地加载的JavaScript文件。

local-file-p-origin-policy

继续在google了一下,找了这个”feature”的由来,https://bugzilla.mozilla.org/show_bug.cgi?id=230606,大概是说本地的文件如果没有这样的限制,可以访问本机的其他文件,这样会造成安全隐患。John Resig(Father of  jQuery) 也有一个blog关于这个问题,http://ejohn.org/blog/tightened-local-file-security/,下面的评论也挺值得看看的。

More Links:

JavaScript中==等同运算符的类型转换

Friday, May 22nd, 2009

这周在给一些新员工讲JavaScript的时候,谈了==和===的区别,本质来说,===是严格的等同运算符,要求两者类型相同并且值相同;而==运算符在做比较时,会做一定的类型转换。我们在使用过程中应该使用===而不是==,因为这种类型转换后的比较往往都不是你想要的。当时列出了corckfork最喜欢一些例子:

	'' == '0'          // false
	0 == ''            // true
	0 == '0'           // true
	false == 'false'   // false
	false == '0'       // true
	false == undefined // false
	false == null      // false
	null == undefined  // true
	' \t\r\n ' == 0    // true

转换规则

当时有人就问了,那么在做类型转换的时候倒是等式的左边向右边转,还是反过来呢?其实这些都是不对的,我们去看看ECMAScript的规范,会发现它有对于等同运算符做类型转换很明确的比较算法,下面我将其翻译如下:
对于比较x==y,

1.如果x和y类型不同,那么到14步;
//
//2-13步,为类型相同的比较
//
14.如果x是null,y是undefined,返回true;
15.如果x是undefined,y是null,返回true;
16.如果x是Number,y是String,将y转化成Number,然后再比较;
17.如果x是String,y是Number,将x转化成Number,然后再比较;
18.如果x是Boolean,那么将x转化成Number,然后再比较;
19.如果y是Boolean,那么将y转化成Number,然后再比较;
20。如果x是String或者Number,y是Object,那么将y转化成基本类型,再进行比较;
21.如果x是Object,y是String或者Number,将x转化成基本类型,再进行比较;
22.其他情况均返回false;

ECMA这帮人写的算法过程比较啰嗦,简单一句话来概括就是,对于基本类型Boolean,Number,String,三者之间做比较时,总是向Number进行类型转换,然后再比较;如果有Object,那么将Object转化成这三者,再进行比较;对于null和undefined,只有x,y分别是它们时才相同,其他都为false。

另外,对于转化到Number的算法,细节可以来看ECMAScript的规范,但是基本上下面这个几个表可以覆盖大部分的内容:

type-convert to number (+col) : String Values.
“”
(empty
string)
“-1.6″ “0″ “1″ “1.6″ “8″ “16″ “16.8″
+col 0 -1.6 0 1 1.6 8 16 16.8
type-convert to number (+col) : String Values.
“123e-2″ “010″
(Octal)
“0×10″
(Hex)
“0xFF”
(Hex)
“-010″ “-0×10″ “xx”
+col 1.23 10 16 255 -10 NaN NaN
type-convert to number (+col) : Other Values.
undefined null true false new Object() function(){
return;
}
+col NaN 0 1 0 NaN NaN

再回头来看看corkford给出的例子,然后使用上面的规则去判断;

 '' == '0'          // false
//类型相同,毫无疑问,值不同,所以结果为false
 
0 == ''            // true
//String要像Number转化,''是空String,根据上面的表,转成0,所以结果是true
 
0 == '0'           // true
//String要像Number转化,根据上面的转化Number表,'0'转成0,所以结果是true
 
false == 'false'   // false
//有Boolean,转化成Number,所以第一步转化后为0=='false';
//然后'false'向Number转,结果是NaN,最后变成比较0==NaN,那么肯定是false。
//(NaN和任何相比都是false,就算是自己也是false, NaN==NaN //false)
 
false == '0'       // true
//有Boolean,转化成Number,经过第一次转化就成了0=='0';
//就变成了上面的第3个例子,所以是true
 
false == undefined // false
//对于undefined和null,只有两边分别是两者才是true,其他都是false;所以是false
 
false == null      // false
//对于undefined和null,只有两边分别是两者才是true,其他都是false;所以是false
 
null == undefined  // true
//对于undefined和null,只有两边分别是两者才是true,其他都是false;所以是true
 
' \t\r\n ' == 0    // true
//对于String,先转成Number,对于空String,都将转成0,所以转化后成为0==0,结果为true
//(注意,空字符不仅仅是只是空格,还包括\t\r\n等等,更多可以见ECMAScript spec的9.3.1)

总结

虽然我们了解了==这个坏东西的本质,但是在我们的实际JavaScript编程中是要避免使用==,而是去使用===这个严格的比较运算符。

在Mac机上搭建Projectzero的Build环境

Monday, November 24th, 2008

一直想在本地建立zero的Build环境,无奈总是太耗时,也没有机器,现在有了mac在旁边,当然要拿它来做build的环境了。最近几天下班后都要整一会这个,现在终于是过了,在欢快地BUILD,TEST….

所有的应该参考:http://www.projectzero.org/wiki/bin/view/Development/Build。下面一步一步来讲吧。

1. Check out code.

这个比较简单了。对于zero现在不同的版本最好是建立对于的结构,这样以后做不同的build也利于管理。Mac已经内置了svn,所以直接敲就可以了。打开酷酷的Terminal,敲吧。。

mkdir zero
cd  zero
mkdir sebring
mkdir silverstone
cd sebring
mkdir source
cd source
svn checkout https://www.projectzero.org/svn/zero/trunk --username liwenb --password

然后等着吧,喝点咖啡,论坛逛逛。。。。

终于checkout了zero所有的code了,嘿嘿。那么要不试试呗,

cd trunk/BUILD/zero.build/
ant -f zbuild.xml BUILD

很好,开始build了。。。嗯,nice。。。咋啦咋啦,错了?什么标签不支持(我现在是不记得了).看来是因为ant的版本的问题。查查看:

ant -version

哦,原来是1.7,而zero指明需要1.7.1,那么没有办法,安装呗。

2.安装ant 1.7.1

这个倒是简单啦,去http://ant.apache.org/bindownload.cgi.解压,那么到底放到哪里呢?于是查看了一下ant的实际地址。原来mac装在了/usr/share/ant/. 反正我也用不着它的旧的,干脆替换吧。

cp -R apache-ant-1.7.1 /usr/share/ant/

什么什么?没有权限!?查看后是这些文件是root的用户文件。之前也遇到过这个问题,想删除一个root用户的文件,可惜总是没有权限。问了mark老大,也不知道root的用户哪里去了。Google了一把,才知道原来对于Mac机,root用户是需要自己来启动的。好,去启动

3.启动Mac的root用户

当然看到apple的help就可以完成这个了,http://support.apple.com/kb/HT1528

ok,su root, 将ant替换原来的。 好,再试试,ant -f zbuild.xml BUILD。什么错?zso…?OK,zero的build中是需要build一个native的code,对于Mac需要安装Xcode。

4.安装Xcode 到Mac上

默认来说,mac是没有安装这些的。只需要找到第二张安装盘就可以了,很容易就安装上了。如果没有安装盘,那么就可以follow这个来安装了。http://www.macworld.com/article/46286/2005/08/installxcode.html.

好,再来ant -f zbuild.xml BUILD。。。很好,10分钟一直在跑,嗯?eclipse的plugin的build有问题。没办法回去看前提要求吧,原来是需要配置jdk和eclipse的。

5.配置eclipse

这个简单了。到http://aeneis.raleigh.ibm.com/prereqs/eclipse/copy过来,注意download macosx的就好了,根据要求unzipped in your {prereqs directory}/eclipse/3.3.2就可以了。

6.配置JDK

根据Michael的说明,# create a link from zero.build/prereqs/jdks/java5 to  /System/Library/Frameworks/JavaVM.framework/Versions/1.5/Home

好ln java5 …..

7.完成,:)

再ant -f zbuild.xml BUILD,等上15分钟,就可以看到success的信息了。如果你要跑TEST,那可能就要等好几个小时了。

P.S. 本来是上周末的文章,放到draft就到了现在,kaka..

依然呐喊…

Tuesday, October 28th, 2008
依旧呐喊

Page as a mp3 player

Thursday, May 29th, 2008

SoundManager 2是一个Audio的javascript  API。可以到http://schillmania.com/projects/soundmanager2/上看看,有很多的demo,很是有意思。其中我非常喜欢第一个demohttp://schillmania.com/projects/soundmanager2/demo/page-player/
,和以前的那些flash的播放器很不一样。我不需要嵌什么,不需要那么复杂,只需要歌曲列在那里,我点击就可以播放了,就像看一篇文章一样,一切都是那么自然。

我准备把我的http://liwenbing.cn/music/整成这个样子,敬请关注吧。

IE中奇怪的status code 1223

Thursday, May 8th, 2008

又是IE,为什么老是你?今天处理一个IE和firefox不兼容的问题,最后的原因是因为IE的一个奇怪的HTTP status code 1223.原来,IE会将HTTP的204(No Content)转换成它内部的status code 1223,就会产生这个问题。本来期望dojo能屏蔽这个问题,但是看来它并没有按照期望的方式进行处理。status code还是1223返回,并且作为error来抛给Error callback给处理。

解决的办法可以是在error的时候去判断处理:(感觉不是很好)

1
2
3
4
5
6
7
error:function(err, ioArgs){
    if(dojo.isIE&&ioArgs.xhr.status==1223){
       //do something
    }else{
        //handle error
    }
}

Some links:
http://vegdave.wordpress.com/2007/11/05/1223-status-code-in-ie/
http://trac.dojotoolkit.org/ticket/2418
https://groups.google.com/group/jquery-en/browse_thread/thread/8136195c67c9819b

在dojo中处理IE和Firefox的常见的兼容性问题

Wednesday, May 7th, 2008

让javascript在不同的浏览器之间兼容就是一件pains-taking的事情,虽然dojo已经封装了不同浏览器之间的 大部分差异,在实际使用dojo进行开发的时候,仍然偶尔会遇到此类问题。
近一段时间又在做这个工作,也将这些tips记录如下。这些内容也是在组里人在处理这些问题不断总结的出来。

  1. Object的定义不严格(可以说最容易出错的地方):
    实例:

    var obj = {a:"ha",b:"he",}; //Error in IE

    原因:
    这个会在IE中出错,但是在firefox中work。原因就是在IE中Object后面不允许多一个逗号,其实ECMAScript上面的确定义这个是不合法的,只能说IE在这种地方还真是遵循标准。在新的JavaScript 5中,这个将会是合法。
    解决办法:
    去掉逗号,如上例{a:”ha”,b:”he”}。在Eclipse中可以用如下正则表达式来需找这种不合法的使用:,\s*}

  2. javascript 的Array的定义不一样
    实例:

    [1,2,3,].length === 3 //  FF
    [1,2,3,].length === 4 // IE

    错误原因及修正:
    这个麻烦的是IE并不会报语法错误,所以更要小心。注意在array的定义中请去掉逗号。在JavaScript 5中,IE将更正这个bug。

  3. 非显式局部变量声明
    实例:

    self = this;
    self.a = {};

    原因以及修改办法:
    IE中不允许隐式声明局部变量,任何局部变量必须通过类似var a = xx的方式进行显式声明

  4. 直接设dom节点的class属性
    实例:

    dom.setAttribute("class","xx")

    错误原因:
    并不是所有的属性都可以使用setAttribute来设置的。在IE中设置class实际上要使用className。这个link中给出了所有的不兼容的属性,要避免使用setAttribute设置这些属性。http://webbugtrack.blogspot.com/2007/08/bug-242-setattribute-doesnt-always-work.html
    解决办法:
    使用dojo,当然尽量使用dojo的方法出处理这些问题。或者按照上面的link给出的办法去处理。

  5. IE ,Firefox 的CSS 的hover机制不同
    描述:
    在Firefox中,css的hover可以针对所有的HTML节点 ,like DIV,SPAN…,但是在IE中,hover的对象是有限制的,现在是可以对hyperlike可以进行hover.

    错误原因及修正:
    尽量使用<a></a>来wrap所需要hover的元素。
    或者使用js中onMourseOver触发事件更改style

  6. IE 的table在创建时TR必须要append到tbody上
    描述:
    在Firefox中,TR可以直接append到table上面,但是在IE中,直接的append会导致TR显示不出来。
    错误原因及修正 :
    这个是一个IE DOM API一个不兼容的问题,具体细节可以看下面两个链接。解决办法当然是每次在东西创建table时,也需要创建tbody,然后见TR append到tbody中。

    具体可以看:http://www.quirksmode.org/dom/w3c_html.html#t03
    原因可以看:http://www.ericvasilik.com/2006/07/code-karma.html

  7. IE 6.0 以下版本Select Element问题
    问题描述:
    在IE 60 以下版本中的Select Element无论其z-index 设为何值,其均在任何Div之上,对于有拖动div的页面,应该考虑进行改进。
    详细的Test Case 请参见: [1] 中的4. Bug: SELECT elements ignore Z-index (“windowed element” problem)
    解决方法 :
    1.Dojo中使用 dojoType 为dijit.form.ComboBox的 Select Element会将其parse成为input Box,从而解决此问题。
    2.Google的GWT中将每个Div下添加一个iframe 元素,使其能够掩盖Select Element。