|
2007年10月12日
Nokia在Maxis推廣Widget的時(shí)候告訴我Widget只能在S603.2上運(yùn)行,所有S603.0系列手機(jī)可以通過軟件升級(jí)來支持這個(gè)新功能
Baidu一把,發(fā)現(xiàn)一大把人在說不能升級(jí)到S603.2,那不和Nokia的說法矛盾,Google一把Nokia software upgrade,找到一個(gè)自動(dòng)更新程序
連上手機(jī),可以自己幫你識(shí)別你的電話是否有最新軟件升級(jí)可用,花了10多分鐘就下載完114Mb的升級(jí)文件,然后又花了5分鐘刷機(jī)成功,開機(jī)后感覺速度沒有太大提升,反而鈴聲沒有以前清脆了,我一款短信鈴聲以前聽起來高音非常不錯(cuò),現(xiàn)在聽有爆音了.......馬上測(cè)試了下我自己開發(fā)的Widget,果然可以識(shí)別并提示安裝,裝好了就和普通的Symbian Application一樣,不錯(cuò),又有得玩了........
但是由于一直沒有查到S60的版本查看方法,所以我始終不知道我到底是不是升級(jí)到了3.2,如果有人知道,麻煩留言告訴一聲
好像國內(nèi)對(duì)Adobe的新產(chǎn)品AIR反應(yīng)還不多,我個(gè)人試用了下覺得其實(shí)用處還是很大的,于是我就拋磚引玉寫一篇相關(guān)介紹文章吧
AIR其實(shí)是一套框架和一個(gè)VM,它允許用戶把Javascript,HTML,CSS集成到統(tǒng)一的客戶端,在用戶桌面運(yùn)行,避免了瀏覽器差異,并且實(shí)現(xiàn)了跨平臺(tái)的通用性,同時(shí)又對(duì)Javascript功能進(jìn)行了很多擴(kuò)展,比如讀取本地磁盤文件,做跨域的遠(yuǎn)程訪問,使用多媒體文件等等(相信是flash的底層在支持),相對(duì)于兩年前的Flex,AIR在RIA領(lǐng)域無疑又是一個(gè)跨越,想象一下以后我們可以用JS+HTML+CSS來寫基于http的遠(yuǎn)程且防火墻安全的C/S應(yīng)用了,還是蠻爽吧
Demo在這里:http://labs.adobe.com/showcase/air/?promoid=BJXTF
用JS來寫應(yīng)用的文檔在這里:http://livedocs.adobe.com/labs/air/1/devappshtml/
Adobe AIR出新版SDK后,出乎意料的是很多之前的Demo不能跑了,會(huì)出"parsing disallowed",原因就是adobe換用了新的安全框架,禁止掉了Javascript中某些可能對(duì)其框架做出安全威脅的API,比如說JSON的命根--eval
Adobe的官方解釋是在AIR2禁止掉了類似eval這種動(dòng)態(tài)代碼加載技術(shù)在其Application sandbox中的運(yùn)行,解決辦法是把你有eval的應(yīng)用移到Browse sandbox中執(zhí)行,所謂的Browse sandbox意思是你的應(yīng)用主頁面是通過application.xml中配置的根頁面來用iframe引入的,在iframe引入的頁面中你就可以做eval,而把其他如跨域查詢等AIR提供的高級(jí)API操作放到根頁面中去做,然后通過一個(gè)parent/childSandboxBridge來做互相引用和傳遞數(shù)據(jù)的橋梁,但是同時(shí)你在iframe中的js也不能直接使用AIR所提供的一些高級(jí)API,比如air.trace().原文的解釋在這里
,Adobe甚至還寫了一篇文章來鼓吹這種方式其實(shí)更符合設(shè)計(jì)模式--根頁面負(fù)責(zé)數(shù)據(jù)傳遞,iframe頁面負(fù)責(zé)業(yè)務(wù)邏輯.但是無論如何這篇文章作為Browse sandbox的入門來講還是很值得細(xì)讀的
于是結(jié)合自己當(dāng)前的實(shí)際需要,我寫了一個(gè)批量查詢airasia.com機(jī)票的小工具,因?yàn)閍irasia從來都是打廣告說從多久到多久,從那里飛到那里才幾塊MYR起! 就是這個(gè)"起"字相當(dāng)關(guān)鍵......直接造成每次我去查的時(shí)候發(fā)現(xiàn)因?yàn)?已經(jīng)快滿坐"了,所以價(jià)格和平時(shí)的一樣,甚至更高,聽同事說他們都是先一天一天去查看哪天便宜就趕快預(yù)定,太辛苦了吧,那我要查2007-11-05到2008-01-31日的機(jī)票要花多少時(shí)間啊,而且不查到最后一天還不知道是不是最便宜的,嘲笑他們?cè)贾笪揖蜎Q定自己寫個(gè)工具來查
所以我寫的第一個(gè)AIR應(yīng)用就是這個(gè)AirAsiaTicketsSearch,可以批量查詢某個(gè)時(shí)間段去和某個(gè)時(shí)間段回的所有機(jī)票,并且把機(jī)票價(jià)格用jQuery.tablesort給排序出來,并且用jQuery.tablesort.page做了分頁(說句題外話,jQuery的tablesort確實(shí)很強(qiáng)大,但是在排序"1,280.00 CNY"這種數(shù)據(jù)的時(shí)候還是有問題).另外開發(fā)環(huán)境值得一說,無論是eclipse+aptana或者aptana standalone都一樣的,aptana就是一個(gè)Eclipse的RCP,關(guān)鍵就是aptana真的是很好用的工具,目前不僅支持AIR,而且還支持開發(fā)Apple iPhone的應(yīng)用,只是專業(yè)版要收費(fèi).....
后面給出截圖,結(jié)果發(fā)現(xiàn)昨天還有295.99的機(jī)票,到了今天就漲到349.99了-_-!

幾個(gè)月前就想弄明白什么是閉包,聽名字多神奇,而且犀牛書上好像也沒有講到,baidu出來的結(jié)果倒是很多很準(zhǔn)確,但是看著那些牛人們翻譯的英文文章,講了上千字我還是沒有明白什么是閉包,遇到復(fù)雜的地方?jīng)]法翻譯還只能引用原文來解釋,本來我的FF受某個(gè)插件影響開CSDN不僅慢還會(huì)停止響應(yīng)10多秒,我都是忍痛點(diǎn)下CSDN的連接,結(jié)果看到這種垃圾文章真是讓人憤怒,寫了一大堆,最后還是不能讓人明白他到底想要解釋什么是閉包,還是炫耀他對(duì)技術(shù)的理解,還是要滿足他對(duì)翻譯的狂熱.
結(jié)果今天終于看到一篇 Morris Johns的文章,用了不到5分鐘就把閉包是什么講的清清楚楚,比如文章中有一句話:
In JavaScript, if you use the function
keyword inside another function, you are creating a closure.
媽的,還有比這更簡(jiǎn)單的解釋嗎,為什么那些國內(nèi)所謂的牛人就是寫不出這種平實(shí)的話,就非要浪費(fèi)自己和別人的時(shí)間講一堆貌似浮云的定義,我覺得他們真的該思考下自己寫技術(shù)文章的目的,是為了在傳遞知識(shí),還是在滿足自己的虛榮,如果是后者,建議直接在Tag中注明"自慰貼",免得浪費(fèi)大家的時(shí)間.
在后面的文章中,作者列舉了很多生動(dòng)的例子,每個(gè)例子后面的解釋都非常平實(shí),沒有任何為了表現(xiàn)自己能力的華麗辭藻,通過他的例子,我很快理解的閉包的特點(diǎn),可以用來做什么,前后不到30分鐘,回想我?guī)讉€(gè)月前光是找合適的解釋就找了近一個(gè)小時(shí).
當(dāng)我對(duì)閉包的特點(diǎn)已經(jīng)諳熟于心后,作者再開始講一些抽象的定義,讓人感覺沒有一點(diǎn)障礙,就如作者自己的話:
If everything seems completely unclear then
the best thing to do is to play with the examples. Reading an explanation is
much harder than understanding examples.
My explanations of closures and stack-frames etc are not technically correct
- they are gross simplifications intended to help understanding. Once the
basic idea is grokked, you can pick up the details later.
最后給出那篇文章的地址,相信不懂閉包的人也能像我一樣很快就理解,同時(shí)也希望大家看完后別忘了別人踏踏實(shí)實(shí)寫技術(shù)文章的態(tài)度
http://www.javascriptkit.com/javatutors/closures.shtml
最近寫AJAX的應(yīng)用遇到很多需要豐富的Javascript集合的地方,可惜javascript沒有Java的Collection那么強(qiáng)大的集合類,于是打算自己嘗試寫一個(gè)模擬Set的API,結(jié)果寫出來的模擬類和Set有點(diǎn)不同,有一個(gè)優(yōu)勢(shì)--可以有序取單個(gè)對(duì)象,但也有一個(gè)劣勢(shì),就是刪除單個(gè)對(duì)象需要遍歷該集合,由于我的應(yīng)用不大可能用到單個(gè)刪除,所以我暫時(shí)還沒有想到一種數(shù)據(jù)結(jié)構(gòu)可以實(shí)現(xiàn)不遍歷的單個(gè)對(duì)象刪除,又能滿足現(xiàn)有的API都高效完成,如果誰有更好的代碼來實(shí)現(xiàn)請(qǐng)回復(fù)
目前想到可以實(shí)現(xiàn)的方法:
add(o);
addAll(array)
contain(o);
get(int);
getAll();
sort(comparator); //傳進(jìn)去的是一個(gè)fn,還沒有寫例子....
size();
remove();
reverse();
基本數(shù)據(jù)結(jié)構(gòu)是兩個(gè)數(shù)組,一個(gè)是index數(shù)組,數(shù)組下標(biāo)連續(xù),用來存放第二個(gè)數(shù)組的下標(biāo),另一個(gè)是存放對(duì)象的數(shù)組,不連續(xù),下標(biāo)是對(duì)象的id或者對(duì)象中其他任何可以轉(zhuǎn)換成唯一Integer的Field(Set也要求放進(jìn)去的對(duì)象必須要有hashCode嘛,不然沒法區(qū)別第一個(gè)和第二個(gè))
實(shí)現(xiàn)的API:
function Collection(){
this.chain=new Array();
this.table=new Array();
}
Collection.prototype.get=function(i){
return this.table[this.chain[i]];
}
Collection.prototype.add=function(o){
this.table[o.id]=o;
this.chain.push(o.id);
}
Collection.prototype.addAll=function(array){
for(var _i=0;_i<array.length;_i++){
this.add(array[_i]);
}
}
Collection.prototype.contain=function(o){
if(this.table[o.id]){
return true;
}else{
return false;
}
}
Collection.prototype.getAll=function(){
tempList=new Array();
for(var _i=0;_i<this.chain.length;_i++){
tempList.push(this.table[this.chain[_i]]);
}
return tempList;
}
Collection.prototype.sort=function(comparator){
this.chain.sort(comparator);
}
Collection.prototype.remove=function(o){
var _var = this.chain;
for(var _i=0;i<this.chain.length;i++){
if(this.table[this.chain[_i]].id==o.id){
this.table[this.chain[_i]]=null;
this.chain.splice(_i,1);
return;
}
}
}
Collection.prototype.size=function(){
return this.chain.length;
}
Collection.prototype.reverse=function(){
this.chain.reverse();
}
目前還有一個(gè)addAll方法也是暫時(shí)沒有想到有什么不用遍歷的好的實(shí)現(xiàn)
前同事提供了一種完全和Set一樣的實(shí)現(xiàn),效率滿高
function Map(){
this.obj = {};
this.count = 0;
}
Map.prototype.put = function(key, value){
var oldValue = this.obj[key];
if(oldValue == undefined){
this.count++;
}
this.obj[key] = value;
return oldValue;
}
Map.prototype.get = function(key){
return this.obj[key];
}
Map.prototype.remove = function(key){
var oldValue = this.obj[key];
if(oldValue != undefined){
this.count--;
delete this.obj[key];
}
return oldValue;
}
Map.prototype.size = function(){
return this.count;
}
function Set(getKey){
this.map = new Map();
this.getKey = getKey;
}
Set.prototype.add = function(value){
var key = this.getKey(value);
this.map.put(key, value);
}
Set.prototype.remove = function(value){
var key = this.getKey(value);
this.map.remove(key);
}
Set.protorype.getAll=function(){
tempArray=new Array();
for(var i in this.obj){
tempArray.push(i);
}
return tempArray;
}
Set.prototype.size = function(){
return this.map.size();
}
還有一個(gè)朋友的實(shí)現(xiàn)和我最初的差不多,但是remove方法相當(dāng)有創(chuàng)意,用正則表達(dá)式來刪除
Collection.prototype.remove=function(o){
var _var = this.chain;
this.table[o.id]=null;
var re = new RegExp("(^["+o.id+"]$)|(^["+o.id+"][,])|([,]["+o.id+"]$)","g");
var s = "["+this.chain.toString().replace(re,"").replace(","+o.id+",",",")+"]";
this.chain=eval(s)
}
有人回復(fù)說需要添加做驗(yàn)證,我覺得不必了,如果添加的值和之前的一樣就直接替換好了,如果希望不被replace,直接在添加新對(duì)象之前用contain判斷一次就可以了,畢竟在我的實(shí)現(xiàn)中已不是完全在模擬Set了,目前更傾向于設(shè)計(jì)一個(gè)更高效和強(qiáng)大的集合類
|