2009年9月28日星期一

[转]JavaScript的线程模型

JavaScript的setTimeout与setInterval是两个很容易欺骗别人感情的方法,因为我们开始常常以为调用了就会按既定的方式执行, 我想不少人都深有同感, 例如

setTimeout( function(){ alert('你好!'); } , 0);
setInterval( callbackFunction , 100);

认为setTimeout中的问候方法会立即被执行,因为这并不是凭空而说,而是JavaScript API文档明确定义第二个参数意义为隔多少毫秒后,回调方法就会被执行. 这里设成0毫秒,理所当然就立即被执行了.
同理对setInterval的callbackFunction方法每间隔100毫秒就立即被执行深信不疑!

但随着JavaScript应用开发经验不断的增加和丰富,有一天你发现了一段怪异的代码而百思不得其解:

div.onclick = function(){
setTimeout( function(){document.getElementById('inputField').focus();}, 0);
};

既然是0毫秒后执行,那么还用setTimeout干什么, 此刻, 坚定的信念已开始动摇.

直到最后某一天 , 你不小心写了一段糟糕的代码:

setTimeout( function(){ while(true){} } , 100);
setTimeout( function(){ alert('你好!'); } , 200);
setInterval( callbackFunction , 200);

第一行代码进入了死循环,但不久你就会发现,第二,第三行并不是预料中的事情,alert问候未见出现,callbacKFunction也杳无音讯!

这时你彻底迷惘了,这种情景是难以接受的,因为改变长久以来既定的认知去接受新思想的过程是痛苦的,但情事实摆在眼前,对JavaScript真理的探求并不会因为痛苦而停止,下面让我们来展开JavaScript线程和定时器探索之旅!

拔开云雾见月明

出现上面所有误区的最主要一个原因是:潜意识中认为,JavaScript引擎有多个线程在执行,JavaScript的定时器回调函数是异步执行的.

而事实上的,JavaScript使用了障眼法,在多数时候骗过了我们的眼睛,这里背光得澄清一个事实:

JavaScript引擎是单线程运行的,浏览器无论在什么时候都只且只有一个线程在运行JavaScript程序.

JavaScript引擎用单线程运行也是有意义的,单线程不必理会线程同步这些复杂的问题,问题得到简化.

那么单线程的JavaScript引擎是怎么配合浏览器内核处理这些定时器和响应浏览器事件的呢?
下面结合浏览器内核处理方式简单说明.

浏览器内核实现允许多个线程异步执行,这些线程在内核制控下相互配合以保持同步.假如某一浏览器内核的实现至少有三个常驻线 程:javascript引擎线程,界面渲染线程,浏览器事件触发线程,除些以外,也有一些执行完就终止的线程,如Http请求线程,这些异步线程都会产 生不同的异步事件,下面通过一个图来阐明单线程的JavaScript引擎与另外那些线程是怎样互动通信的.虽然每个浏览器内核实现细节不同,但这其中的 调用原理都是大同小异.


由图可看出,浏览器中的JavaScript引擎是基于事件驱动的,这里的事件可看作是浏览器派给它的各种任务,这些任务可以源自 JavaScript引擎当前执行的代码块,如调用setTimeout添加一个任务,也可来自浏览器内核的其它线程,如界面元素鼠标点击事件,定时触发 器时间到达通知,异步请求状态变更通知等.从代码角度看来任务实体就是各种回调函数,JavaScript引擎一直等待着任务队列中任务的到来.由于单线 程关系,这些任务得进行排队,一个接着一个被引擎处理.

上图t1-t2..tn表示不同的时间点,tn下面对应的小方块代表该时间点的任务,假设现在是t1时刻,引擎运行在t1对应的任务方块代码内,在这个时间点内,我们来描述一下浏览器内核其它线程的状态.

t1时刻:

GUI渲染线程:

该线程负责渲染浏览器界面HTML元素,当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行.本文虽然重 点解释JavaScript定时机制,但这时有必要说说渲染线程,因为该线程与JavaScript引擎线程是互斥的,这容易理解,因为 JavaScript脚本是可操纵DOM元素,在修改这些元素属性同时渲染界面,那么渲染线程前后获得的元素数据就可能不一致了.

JavaScript引擎运行脚本期间,浏览器渲染线程都是处于挂起状态的,也就是说被"冻结"了.

所以,在脚本中执行对界面进行更新操作,如添加结点,删除结点或改变结点的外观等更新并不会立即体现出来,这些操作将保存在一个队列中,待JavaScript引擎空闲时才有机会渲染出来.

GUI事件触发线程:

JavaScript脚本的执行不影响html元素事件的触发,在t1时间段内,首先是用户点击了一个鼠标键,点击被浏览器事件触发线程捕捉后形成 一个鼠标点击事件,由图可知,对于JavaScript引擎线程来说,这事件是由其它线程异步传到任务队列尾的,由于引擎正在处理t1时的任务,这个鼠标 点击事件正在等待处理.

定时触发线程:

注意这里的浏览器模型定时计数器并不是由JavaScript引擎计数的,因为JavaScript引擎是单线程的,如果处于阻塞线程状态就计不了时,它必须依赖外部来计时并触发定时,所以队列中的定时事件也是异步事件.

由图可知,在这t1的时间段内,继鼠标点击事件触发后,先前已设置的setTimeout定时也到达了,此刻对JavaScript引擎来说,定时触发线程产生了一个异步定时事件并放到任务队列中, 该事件被排到点击事件回调之后,等待处理.
同理, 还是在t1时间段内,接下来某个setInterval定时器也被添加了,由于是间隔定时,在t1段内连续被触发了两次,这两个事件被排到队尾等待处理.

可见,假如时间段t1非常长,远大于setInterval的定时间隔,那么定时触发线程就会源源不断的产生异步定时事件并放到任务队列尾而不管它 们是否已被处理,但一旦t1和最先的定时事件前面的任务已处理完,这些排列中的定时事件就依次不间断的被执行,这是因为,对于JavaScript引擎来 说,在处理队列中的各任务处理方式都是一样的,只是处理的次序不同而已.

t1过后,也就是说当前处理的任务已返回,JavaScript引擎会检查任务队列,发现当前队列非空,就取出t2下面对应的任务执行,其它时间依此类推,由此看来:

如果队列非空,引擎就从队列头取出一个任务,直到该任务处理完,即返回后引擎接着运行下一个任务,在任务没返回前队列中的其它任务是没法被执行的.

相信您现在已经很清楚JavaScript是否可多线程,也了解理解JavaScript定时器运行机制了,下面我们来对一些案例进行分析:

案例1:setTimeout与setInterval

setTimeout(function(){
/* 代码块... */
setTimeout(arguments.callee, 10);
}, 10);

setInterval(function(){
/*代码块... */
}, 10);

这两段代码看一起效果一样,其实非也,第一段中回调函数内的setTimeout是JavaScript引擎执行后再设置新的setTimeout 定时, 假定上一个回调处理完到下一个回调开始处理为一个时间间隔,理论两个setTimeout回调执行时间间隔>=10ms .第二段自setInterval设置定时后,定时触发线程就会源源不断的每隔十秒产生异步定时事件并放到任务队列尾,理论上两个setInterval 回调执行时间间隔<=10.

案例2:ajax异步请求是否真的异步?

很多同学朋友搞不清楚,既然说JavaScript是单线程运行的,那么XMLHttpRequest在连接后是否真的异步?
其实请求确实是异步的,不过这请求是由浏览器新开一个线程请求(参见上图),当请求的状态变更时,如果先前已设置回调,这异步线程就产生状态变更事件放到 JavaScript引擎的处理队列中等待处理,当任务被处理时,JavaScript引擎始终是单线程运行回调函数,具体点即还是单线程运行 onreadystatechange所设置的函数.

[转]Javascript的instanceof方法

在 JavaScript 中,可以用 instanceof 来判断一个对象是不是某个类或其子类的实例。比如:

// 代码 1
function Pig() {}
var pig = new Pig();
alert(pig instanceof Pig); // => true

function FlyPig() {}
FlyPig.prototype = new Pig();
var flyPig = new FlyPig();
alert(flyPig instanceof Pig); // => true

来看另一段代码:

// 代码 2
function Pig() { Pig.prototype = {/* some code */} }
var pig = new Pig();
alert(pig instanceof Pig); // => false

为何上面的猪 pig 不再是猪 Pig 了呢?

当一个对象是某个类的实例时,意味着这个对象具有该类的方法和属性。在 JavaScript 中,一个猪类的特性体现在原型中:

// 代码 3
function Pig() {}
Pig.prototype = {
"吃猪食": function() {},
"睡觉": function() {},
"长膘": function() {}
};
var pig = new Pig();
alert(pig instanceof Pig); //=> true

如果动态改变了猪的特性,让猪变成了牛:

// 代码 4
Pig.prototype = {
"吃草": function() {},
"犁田": function() {}
};
var niu= new Pig();
alert(pig instanceof Pig); //=> false
alert(niu instanceof Pig); //=> true

当未改变 Pig 的 prototype 时,猪还是猪,因此代码 3 中 pig 是 Pig 的实例。当改变 prototype 后,猪已经不是猪,而是披着猪皮的牛了。因此代码 4 中 pig 不再是 Pig 的实例,niu 反而是 Pig 的实例。

进一步分析前,先回顾一下 new 的内部机制。代码 2 中的 new Pig() 实际上等价为:

// var pig = new Pig() 的等价伪代码:
var pig = (function() {
var o = {};
o.__proto__ = Pig.prototype; // line 2
Pig.call(o);
Pig.prototype = {/* some code */}; // line 4
return o; // line 5
})();

可以看出,在 line 2 时,o.__proto__ 指向了 Pig.prototype 指向的值。但在 line 4 时,Pig.prototype 指向了新值。也就是说,在 line 5 返回时,pig.__proto__ !== Pig.prototype. 正是这个变化,导致了代码 2 中的 pig 不是 Pig.

已经可以大胆推论出:instanceof 判断 pig 是不是 Pig 的依据是:看隐藏的 pig.__proto__ 属性是否等于 Pig.prototype !

为了进一步确认,我们可以在 Firefox 下模拟 instanceof 的内部实现代码:

/**
* Gecko 引擎下,模拟 instanceof
*/
function _instanceof(obj, cls) {
// instanceof 的左操作数必须是非null对象或函数对象
if((typeof obj !== "object" || obj === null)
&& typeof obj !== "function") {
return false;
}

// instanceof 的右操作数必须是函数对象
if(typeof cls !== "function") {
throw new Error("invalid instanceof operand (" + cls + ")");
}

// 向上回溯判断
var p = obj.__proto__, cp = cls.prototype;
while(p) {
if(p === cp) return true;
p = p.__proto__;
}
return false;
}

测试页面:simulate-intanceof.html

最后考考大家:

function Bird() {}
var bird = new Bird();
var o = {};
bird.__proto__ = o;
Bird.prototype = o;
alert(bird instanceof Bird); // true or false?

2009年9月27日星期日

[转]生活急救小常识

日常生活中,意外伤害很难避免,有时也难以预料,如果我们不及时医治或者操作不当的话,很可能会对自身或者他人的身体造成伤害,所以,掌握一些急救常识是非常必要的。下面就看一下我们日常生活中经常遇到小意外的处理方法,希望对大家有所帮助。

眼睛里不慎进了沙子

眼睛是最娇嫩的器官,容不得任何异物。如不及时清除异物,眨眼时会感到疼痛,还会引起炎症、溃烂甚至失明。异物入眼时,最忌讳使劲揉眼睛,或用干的 纸巾 或毛巾擦拭眼睛。正确的做法是睁开眼睛,让同伴帮忙翻开眼皮,仔细检查眼白(球结膜)、下眼睑和角膜。如异物在眼皮或眼白部位,可用纸巾蘸少许纯水轻轻擦 去异物(在家时,最好用棉签沾少许抗生素类眼药水擦去异物);如异物在上眼睑内、角膜处,或嵌入较深,则必须及时到医院处理。

鱼骨卡喉

鱼骨卡喉后,应立即停止进食,张大嘴发"啊"的声音,让家属借助光线或手电筒,看清鱼骨所在部位,再用镊子夹出。若未发现鱼骨,则鱼骨可能卡在更深 的喉 咽部,应去医院就诊。鱼骨取出后,在短时间内仍然会有咽喉部异物感,这是局部黏膜擦伤的缘故,不必介意。不少人喜欢采用吞咽大的干饭团的方法来对付鱼骨卡 喉,该方法对小的鱼骨可能有效,但对稍大一些的鱼骨则无效,有时反而会因挤压而刺得更深。还有些人认为,一旦鱼骨卡喉,可少量多次吞服食用醋使鱼骨溶解。 其实,食醋在咽喉部停留的时间很短,根本不可能溶解鱼骨。

小飞虫钻进了耳道

小飞虫突然钻进耳道后,千万不要用手指或其他东西去掏它,以免小飞虫越钻越深,万一钻破鼓膜,可引起听力下降。正确的做法是到黑暗的地方,用手电光 照着 耳道,利用昆虫的趋光性,用光引出飞虫。也可以在耳道内滴几滴烹调油,使飞虫的翅膀浸湿而无法张开,再用耳勺将虫掏出耳道。若上述方法不奏效,应立即去医 院就诊。

吃东西被噎

如果患者还能讲话或咳嗽,表明气道没有被完 全阻塞,尽量让他自己咳出较好;如果患者意识清醒,但无法自己咳出噎住的食物,可用海姆利克操作法(如下图),即顺着患者的上腹部向上迅速施压,靠产生的 冲击气流将食物挤出气道;如果患者已呼之不应,应立刻扳开他的嘴,用食指贴着其口角一侧,伸入到口腔深部向外做钩扫动作,直至清除食物为止。若以上尝试均 不奏效,应立即送医院急诊。

急救常识

鼻出血

鼻出血时仰头,非但止不住鼻血,反而会导致鼻血被吸入口腔和呼吸道。正确的做法是用手指捏住两侧鼻翼4~8分钟,或用浸了冰水的棉球填塞鼻腔压迫止血。如果这些方法仍不能止血,应立即去医院就诊。

醉酒

轻度醉酒者,可以让其喝浓茶利尿,加速酒精的排泄。严重醉酒者,可让其喝醋,并用手指压迫其舌根催吐,以减少酒精的吸收。若上述处理效果不明显,应送医院处理。

中暑

轻中度中暑者,应将其迅速转移到阴凉通风处静卧休息,脱掉或解开衣服,用冷毛巾擦身,以迅速降低体温。可让中暑者喝一些凉盐水、清凉含盐饮料。若患者出现神志不清、抽搐,应立即送医院。

晒伤

夏天外出时,应做好防护工作,比如搽防晒霜、撑遮阳伞等。当皮肤被烈日晒红并出现红肿、疼痛时,可用冷毛巾敷于患处,并适当涂一些滋润霜。若皮肤上已有水疱,千万不要挑破,应请医生处理,以免继发感染。

蜂蜇伤

外出郊游一旦被蜜蜂蜇伤,应小心地将残留的毒刺拔出,轻轻挤捏伤口,挤出毒液,涂一点氨水或苏打水。若是被黄蜂蜇伤,应涂醋酸水,以中和毒液。局部冷敷可减轻肿痛。若出现恶心、头晕等异常反应,应立即去医院就诊。

游泳时,小腿抽筋

在水中发生小腿抽筋时,应立即上岸,伸直腿坐下,用手抓住大足趾向后拉,并按摩小腿肌肉。若不能立即上岸,应保持冷静,屏住气,在水中做上述动作。

不慎咬碎体温表并吞服了水银

体温表内的水银不慎被吞服后,汞会与体内含巯基的酶和蛋白质结合,影响其活性,导致重金属中毒。尽管体温表内的汞含量不多,但服用后也会引起口腔 炎、急 性胃肠炎,表现为口腔糜烂、溃疡,腹痛、恶心、呕吐、腹泻等。漱口后喝点蛋清或牛奶,不仅能清除口腔中的残留汞,还能使蛋清或牛奶中的蛋白质与吞服的汞结 合,起到保护胃黏膜、减少汞吸收的作用。

外伤出血

①较小或较表浅的伤口,应先用冷开水或洁净的自来水冲洗,但不要去除已凝结的血块。

②伤口处有玻璃片、小刀等异物插入时,千万不要去触动、压迫和拔出,可将两侧创缘挤拢,用消毒纱布、绷带包扎后,立即去医院处理。

③碰撞、击打的损伤,有皮下出血、肿痛,可在伤处覆盖消毒纱布或干净毛巾,用冰袋冷敷半小时,再加压包扎,以减轻疼痛和肿胀。伤势严重者,应去医院。

④伤口有出血,可用干净毛巾或消毒纱布覆盖伤处,压迫10~20分钟止血,然后用绷带加压包扎,以不再出血为度,视情况去医院处理。

刀割伤

①如伤口不大,出血不多,伤口也较干净,伤指仍能作伸屈活动,可用医用碘消毒伤口及其周围皮肤,待干后,再用消毒纱布或创可贴覆盖包扎伤口。

②若伤口大而深,应压迫止血,同时立即去医院治疗。

③如果手指不幸被切断,应立即将伤指上举,然后用干净的纱布直接加压包扎伤口止血。若血仍外流不止,也可在指根处紧缠止血带(可用一般的清洁绳代 替)止 血,并将断指用无菌布料包好,放入干净的塑料袋中。除非断指污染特别严重,一般不要自己冲洗,也不要用任何液体浸泡断指,立即去医院救治。

烫伤

一旦发生烫伤,应立即用冷水冲洗或冷敷烫伤部位,持续15分钟左右,以缓解疼痛,减轻烫伤程度。不要擅自在伤口处涂药,更不能用涂酱油、植物油等土办法处理伤口。若烫伤处有水疱,不要挑破,可用干净纱布覆盖,去医院处理。

骨折

确定有骨折后,一定要对伤肢(指)作固定再送医院,否则骨折断端异常活动,会加重损伤。可因地制宜用木板、木棍、树枝、竹竿、杂志等作为固定用的临时夹板。若无上述材料,可将上肢固定在躯干上,下肢固定在对侧的健肢上。

气胸

有些人,特别是老年慢阻肺患者,在用力咳嗽、剧烈运动或大笑后,会发生气胸,出现胸痛、深吸气时加剧,并放射到肩背部,严重时,还会出现呼吸困难、 血压 下降等紧急情况。遇到这种情况,禁忌拍背和搬动患者,以免加重气胸。应让患者取半卧位,如家中备有氧气,应立即吸氧,同时叫救护车。

癫痫发作

在救护车到来之前,可让患者的头侧向一边,以防止呕吐物窒息。随后,找一把金属调羹或牙刷等不易咬碎的东西塞进他的上下牙之间,防止舌咬伤。对于成年人,最好在硬东西上裹一层毛巾或手帕,以免咬掉牙齿。

猫狗咬伤

一些人被动物抓咬后,身上只留有牙印或爪痕,认为没伤口就不必处理,这种做法其实是很危险的。因为牙印或爪痕可能造成肉眼看不到的皮肤损伤,狂犬病病毒也有可能从伤口侵入。

注射疫苗应及早、足量。患者必须于咬伤当天,咬伤后第3天、第7天、第14天、第30天各肌肉注射一支疫苗。一定要注射在上臂三角肌或大腿内侧,不 能注 射在臀部,以免影响疫苗效果。全程注射完毕10日后,应抽取静脉血作抗体检测。如果抗体滴度达到或超过3单位/毫升的标准,即代表获得了免疫效果,如低于 标准,应适当增加接种针数,以确保达到防病效果。

误服灭鼠药

灭鼠药毒性成分不同,误服后的临床表现各异,如胃部不适、呕吐、腹泻、抽搐等,严重的可出现昏迷。喝水稀释、催吐等方法皆难奏效,送医院急诊洗胃或对症处理才是上策。

踝扭伤

踝关节扭伤后,不要继续行走,也不要揉搓、转动受伤关节,以免进一步加重损伤。应立即用冷毛巾或冰块敷患处,有利消肿、止痛、缓解肌肉痉挛。24小 时后 方可改为热敷。如果怀疑有内出血,最好用弹性绷带加压包扎,但不要过紧,以免妨碍包扎部位以下的血液循环。如果怀疑有骨折,最好用夹板或就近找木棍固定受 伤的踝关节,并尽快去医院就诊。

呼吸停止(人工呼吸)

首先,让 伤病员仰卧,将其头后仰,确保呼吸道畅通。若其口内有血块、呕吐物、假牙等异物时,应尽快取出。随后作人工呼吸:抢救者先深吸一口气,然后捏住患者的鼻 子,口对口像吹气球样为其送气,注意不要漏气。每隔5秒吹一次气,反复进行。遇到嘴张不开或口腔有严重外伤者时,可从其鼻孔送气作人工呼吸。

心跳停止(胸外按压)

先让患者躺在硬板床或平整的地上,解开其上衣,抢救者将一只手的掌根置于其胸骨下三分之一的位置,另一只手重叠压在手背上。抢救者两臂保持垂直,以 上身 的重量连续向下按压,频率为每分钟70次左右。按压时,用力要适中,以每次按压使胸骨下陷3~5厘米为度。注意,手掌始终不要脱离按压部位。

心跳呼吸全无(心肺复苏)

呼吸和心跳停止后,大脑很快会出现缺氧,4分钟内将有一半的脑细胞受损。超过5体分钟再施行心肺复苏,只有1/4的人可能救活。

实施心肺复苏时,首先用拳头有节奏地用力叩击患者前胸左乳头内侧的心脏部位2~3次,拳头抬起时,离胸部20~30厘米,以掌握叩击的力量。若脉搏 仍未 恢复搏动,应立即连续做4次口对口人工呼吸,接着再做胸外心脏按压。一人施行心肺复苏时,每做15次心脏按压,再做次人工呼吸。两人合作进行心肺复苏时, 先连做4次人工呼吸,随后,一人连续做5次心脏按压后停下,另一人做一次人工呼吸。

煤气中毒

当发现有煤气泄漏时,正确的做法是立即关闭煤气,开窗透气。抢救者在进入溢满煤气的房间前,应先吸足一口气,然后用湿毛巾或手帕捂住口鼻,以防自己 中 毒。在煤气没有散尽前,不要开灯、按电铃、打电话或使用打火机、火柴等,以免引发爆炸。然后,将中毒者移到通风的地方,松开中毒者的衣领、裤带。观察其意 识、心跳和呼吸情况。如已没有心跳和呼吸,立刻进行人工呼吸和胸外按压;如还有心跳、呼吸,应立即拨打急救电话,送医院进行高压氧治疗,以免留下后遗症。

溺水

救护溺水者时,必须用救生圈、球或木板等,除专职救生员外,即使会游泳的人,也不要徒手接近溺水者。溺水者获救后,应立即检查其呼吸、心跳。如呼吸 停 止,应马上做人工呼吸,先口对口连续吹入4口气,在5秒钟内观察其有无恢复自主呼吸,如无反应,应接着做人工呼吸,直至其恢复自主呼吸。如溺水者呼吸、心 跳全无,应立即实施心肺复苏。如溺水者喝入大量的水,可在其意识清醒时,用膝盖抵住其背部,一手托住上腹部,另一手扒开其口让其吐水,或救护者单腿跪地, 让溺水者脸朝下伏于膝盖上吐水。

气道异物(手捏喉咙,面容窘迫、恐惧等是气道异物的典型症状)

自救:

①用力咳嗽法。先吸一口气,然后用足力气咳嗽,有时就可把异物从气道内咳出。

②腹部手拳冲击法。将右手拇指关节突出点顶住上腹部,相当于剑突与脐之间腹中线部位,左手紧握右手,然后用力向内作4~6次连续快速冲击。

互救:

抢救者站在患者侧后位,一手放置于患者胸部,另一手掌根部对准患者肩胛区脊柱上,用力给予连续4~6次急促拍击。

婴幼儿急救:

让患儿骑跨并俯卧于急救者前臂上,头要低于躯干,并将其胳膊放在自己大腿上,用另一手掌根部用力叩击患儿的肩胛区4~6次。

颈椎损伤

如果怀疑伤员颈椎有损伤,应平抬伤员至担架上,专人牵引、固定其头部,并上颈托。一时无颈托时,应在伤员的颈部两侧各放一只沙袋或衣物,以防头部扭转或屈曲导致颈椎损伤加重。

脊柱骨折

应由3~4人在同一侧同时托住伤员的头、肩、臀和下肢,把伤员平托起来,平卧在木板上,并用绷带加以固定。伤者最好取俯卧位,并在胸腹部放一软枕。严禁采用"搬头搬脚"的抬抱方式移动或搬运伤者,也禁用普通的软担架搬运。

头部撞伤

若伤员伤势较重,已昏迷,抢救者应立即清除其口腔内的呕吐物和血块,将其头转向一侧,牵拉出舌头,以防窒息。血液沿鼻腔和耳道流出时,切勿用棉球、纱布或其他物品堵塞。

需要提醒的是,有时候,人不慎摔倒,枕部着地,表面看来局部无任何皮损,但颅底却已发生骨折。伤者发生颅底骨折后,很快会因颅内出血而出现呼吸困难、恶心呕吐、昏迷等严重症状。因此,当头部被击,伴恶心、呕吐、耳鼻腔出血时,应立即就医。

触电

当发现有人触电时,尽快找到电闸,切断电源是当务之急。如果暂时找不到电源,可就近找一样绝缘的东西,如木棍或塑料管子,挑开触电者与电源的接触,然后 检查触电者的反应。如果发现其已经没有了心跳和呼吸,应立即就地对其进行人工呼吸和胸外按压,同时让别人拨打急救电话。

此外,当意外发生时,如果身边没有医用急救物品,就会错失急救的良机。其实,只要开动脑筋,完全可以因地制宜。这里教你几招,到时不妨一试。

1、长筒袜:可在应急处理时作绷带用。

2、领带:在骨折时,可固定夹板或当止血带用。

3、干净浴巾:可作三角巾或厚敷料用。

4、手帕、手巾:用电熨斗充分熨烫或在湿的情况下用微波炉高火消毒,可作消毒敷料用。

5、杂志、尺、厚包装纸、伞、手杖:在骨折时可作夹板用。

6、保鲜膜:除去表面几圈后,可直接覆盖在破溃的创面上,起暂时的保护作用,保鲜袋也可起类似作用。

原文:我们应该知道的急救小常识

2009年9月20日星期日

昨天玩WOW时的有趣任务

任务名忘了,不过过程很有意思。这个任务得前序任务是75级,后续任务是80级的。

在75级左右时,我从龙眠神殿的青铜龙使者那接到任务去青铜龙神殿解决入侵的邪恶龙人。青铜龙是时间的守护着,所以我在青铜龙神殿放下"时间沙漏"之后,未来的80级的我就出来帮我解决了邪恶龙人。(O(∩_∩)O哈哈~,很轻松!)

昨天80级之后我又在龙眠神殿接到了去青铜龙神殿的任务,这次去就是为了帮助过去的我完成之前的任务,^_^。在青铜龙神殿我看到了过去75级的我,并进行了一些有意思的对话。

<<<话说巫妖王之怒的改动的确很大,游戏的过程中你帮助一个地区的同盟站稳脚跟之后,这个地区你所看到的事和人会和刚进入这个地区的新手所看到的景色不一样,但你又能和这个新手交谈协作。之前也有这种情况,但也是部分任务得小范围情况。很明显暴雪开发了新的服务器逻辑组件,以前范围小可能是消耗太大,而新版一定是做了大量的优化。使得所有的玩家看到的事物都不一样,这样的服务器逻辑我还没想明白,而且它的玩家个数可不是一两千,性能也是值得赞赏的,这可不是中国的游戏公司能办到。果真是暴雪出品,必属精品!>>>

[转]富野作品《高达》所透视出的反战思想

<<<难得看到一篇对动画片的内涵的深刻思考的文章,觉得还行。高达的反战思想我一直很喜欢,深刻的告诉动漫迷战争是残酷的,后宫才是王道!>>>

有关富野悠由季先生的文章有很多,但很少有人去关注、去思考其作品的创作思想,更鲜见将作者的动画创作思想结合其个人特殊的经历而写的文章。故笔者通过对于其动漫作品的深入理解,撰此专文,希望大家可以通过此文更多的去了解这位为日本动漫画做出杰出贡献的大师。

  一部优秀的动画,不仅要有观赏性的外在美感,更重要的是要挖掘和展现在繁杂曲折的经历中所积淀的一种精神,一种因所处的时代和环境的变动,由于学识、修养、品格所形成的精神力量。

  富野先生年轻时历经战争的洗礼,经历坎坷,他亲身经历过第二次世界大战、越南战争。这样的特殊经历让他拥有了一个普通人用尽一生也无法拥有的人生体验。没有亲身经历过战争的恐怖,很难表现明白什么是战争。战争的环境使得其作品拥有非同一般的意味和深度。

   "往事不如烟,惟有反思长在"。战争让人类失去了太多的东西,富野先生一直在反思战争,为了不让战争在记忆中淡化或抹去,富野先生凭着对战争残酷性的深 深理解,自1979年开始,陆续推出了《机动战士高达系列》战争题材动画。这其中,由富野先生导演的第一部作品《机动战士高达0079》(以下简称《高 达》)描写的是在太空时代,地球与外太空殖民地间激烈的利益冲突和由此引发的战争;从正面描写了一个人类在向往宇宙、开发宇宙的进程中战争到底给人来带来 了什么;展现了在战争的背景下,人与人之间,理性与理智之间的激烈冲突与对抗。

  富野先生心中的战争和一般意义上的战争不同,有着极为独 特的、属于他个人的视角对战争的理解。在《高达》这部作品中,一直凸显着人类期盼和平、厌恶战争的内涵情感。他的深深而浓厚的反战思想,透过动漫画,一点 一滴的传达他对人性、生命价值的赞颂和反省,指出战争就是扭曲人性的事:战争让人变得麻木不仁,战争把素不相识的人们推到了一起,同时也揭示露了战争中人 的自私和渺小。

  《高达》片中通过生动的画面,向人们展示了一个个悲壮的战争场景和感人肺腑的真情。反映了战争给人类带来的苦难,揭示了作者超越历史的精神和热爱和平、尊重生命、反对战争之思想,体现了富野先生对战争的感悟和人文精神。

   《高达》的另一大特点,也是他的作品撼动人心之大处,就是认定了战争的非理性与残酷性,教会青少年正确的理解和判断战争。战争只能是一时逞强,不可能解 决所有问题。人们都是被迫的卷入战争,为了生存、自尊或是守候所爱的人而战斗,在这种情况下,无论哪一方的胜利,都只能是以悲剧而告终。当然,结局一定是 正义必胜,正义的力量代表了人类的进步。而就是这样才给予了给观众以极大的震撼,从而产生该片的反战的主题思想。正因为在战争中失去的比得到的更多,才令 人们更加反对战争,厌恶战争。所以富野先生在片子中巧妙的通过剧情的发展告诉我们:我们的社会,很多的时候并不是简单的善恶分明,他们经常是互相交织在一 起,或许对中有错、或许错中有对的辨证思想,这对于青少年的社会成长是很有帮助的。这与我国的动画片对青少年进行单纯的善恶分明的完美式世界观有着明显的 不同,富野先生导演的动画片更多的是再现真实的世界,告诉涉世未深的青少年们,该如何正确看待这个世界上所有的一切,让青少年正确的、客观的去认知世界, 自己去感受对与错、善与恶,树立正确的世界观。

  对于战争,富野先生在《高达》中也提出了自己的解决思想,富野先生认为:无论什么样的冲 突与矛盾,都能通过互相尊重、加深沟通都可得到解决,而战争的手段只会让人类自取灭亡。这正是《高达》系列的真正目的,也是最为人所称道的内涵所在。我想 正是由《高达》所透视出的反战思想,以及富野先生身上的"一切为了和平"的精神,尊重生命的博爱思想所产生出的强大力量,所以,基于此点,他才成就了今天 的《高达》系列,他对动漫画的巨大贡献,不仅在日本人的心中,乃至世界高达迷们的心目中都是无可取代的。

2009年9月17日星期四

[转] javascript中apply方法和call方法的作用以及prototype.js中的应用

call方法在msdn中的解释  调用一个对象的一个方法,以另一个对象替换当前对象。

apply方法在msdn中的解释 应用某一对象的一个方法,用另一个对象替换当前对象。

这个解释也是非常抽象的,这两个方法的作用基本是一样的,举个例子

<script>
function cls1()
{
  this.a='123';
}
cls1.prototype.fun1=function()
{
  alert(this.a);
}
function cls2()
{
  this.a='456';
}
var o1=new cls1();
var o2=new cls2();
o1.fun1.apply(o2);
</script>

只有o1对象的类cls1中有fun1这个方法,但是,这时我们需要用o2对象替代o1对象,所以这个时候显示的this.a会是456,呵呵很神奇吧,换成call方法也是一样的,这两种方法使用的不同点仅仅是参数的使用方法上不同,这里就不多做解释了。

大家可以在prototype.js里看到
var Class = {
  create: function() {
    return function() {
      this.initialize.apply(this, arguments);
    }
  }
}
这种代码,相当的夸张,很多人很容易被这种bt的代码弄糊涂,其实仔细分析其中的道理却也不难

显然这种写法代表了Class是声明的一个Object对象,其中create是这个object对象的一个属性,这个属性就是一个函数。这个函数执行过后返还一个函数。可能这样解释太复杂了,那不如做一个试验好了。

<script>
var x=function(){return function(){alert(123);}}
var n=x();
n();
</script>
 
很好玩吧,这里n就是x函数执行过后返还给的一个函数也就是n现在等于了function(){alert(123);}再执行n()的时候就跳出了123

现在开始讲难点 this.initialize.apply(this, arguments);

这句表达了什么含义,其实现在先看看prototype.js里怎么调用的就明白了

var Template = Class.create();

Template.prototype = {
  initialize: function(template, pattern) {
    this.template = template.toString();
    this.pattern  = pattern || Template.Pattern;
  },....省略代码若干

var template = new Template(replacement);

第一句话Class.create(); 就是返还给Template 一个函数,这个函数是

function() {
      this.initialize.apply(this, arguments);
    }
 
当执行var template = new Template(replacement);时,就变成了要执行这个函数,而这个函数的作用是
执行当前类中initialize这个函数

所以prototype.js中的每一个类都预留了

Template.prototype = {
  initialize: function(template, pattern) {
    this.template = template.toString();
    this.pattern  = pattern || Template.Pattern;
  },....
 
这么个函数,如果没有这个的话,程序将会出错

知其然,知其所以然,为什么要这么写呢?

一般我们声明的时候funciton fun(){} var o=new fun();这样感觉fun又是类又是构造函数很别扭,为了分开这种不是很友好的代码方案,所以prototype.js使用了如上方法  

[bug-fixed]jQuery-SVG插件在IE上使用的注意点!

1. 由于IE本身不支持SVG所以需要安装插件来实现,一般使用adobe-svg-viewer。jQuery-SVG插件在附加SVG图片的时候,由于IE使用的是插件,所以它先附加一个默认的空的SVG图片(blank.svg),这与firefox等其他原生支持svg不同的是firefox只需要加一个<svg ...></svg>标签就可以。这就导致了一个不同点:必需设置initPath属性,否则插件找不到blank.svg图片。如下形式附加空标签:

$('div#svg').svg({initPath:'js/'}); //blank.svg在js文件目录下

(这个问题一直困扰了我1个多小时...看了源码后才明白 )

2. 第二个注意点在于附加svg标签这一步中,代码如下:

$('div#svg').svg({initPath:'js/'});//jquery object
var svgPic = $("div#svg").svg('get');//SVG wrapper object
svgPic.load(mapUrl, {
        changeSize: false,
        onLoad: function (svgg, error) {
            //TODO :载入完成之后需要做的事!
        }}
    );

看起来没什么问题,但是放到IE下就会出现svgPic为“undefined”的情况。
仔细看svg('get');方法源码如下:

var PROP_NAME = 'svgwrapper';   
 
_getSVG: function(container) {
        container = (typeof container == 'string' ? $(container)[0] :
            (container.jquery ? container[0] : container));
        return $.data(container, PROP_NAME);
    },
 
排除一些可能之后,问题在于return $.data(container, PROP_NAME);
这是jQuery的内部函数,功能如下;

jQuery.data( elem, name )

Returns value at named data store for the element.

jQuery.data( elem, name, value )

Stores the value in the named spot and also returns the value.
This function can be useful for attaching data to elements without having to create a new expando. It also isn't limited to a string. The value can be any format.

To avoid conflicts in plugins, it is usually effective to store one object using the plugin name and put all the necessary information in that object.

可见它是用于存储的,而存入这个值的函数在attachSVG方法中,代码如下:
_attachSVG: function(container, settings) {
        .......
        try {
            // firefox等其他浏览器使用   
            var svg = document.createElementNS(this.svgNS, 'svg');
            svg.setAttribute('version', '1.1');
            svg.setAttribute('width', container.clientWidth);
            svg.setAttribute('height', container.clientHeight);
            container.appendChild(svg);
            this._afterLoad(container, svg, settings);
        }
        catch (e) {
            if ($.browser.msie) {
                //IE使用
                if (!container.id) {
                    container.id = 'svg' + (this._uuid++);
                }
                this._settings[container.id] = settings;
                container.innerHTML = '<embed type="image/svg+xml" width="100%" ' +
                    'height="100%" src="' + (settings.initPath || '') + 'blank.svg"/>';
            }
            else {
                //浏览器不支持情况
                container.innerHTML = '<p class="svg_error">' +
                    this.local.notSupportedText + '</p>';
            }
        }
    },
 
    _afterLoad: function(container, svg, settings) {
        var settings = settings || this._settings[container.id];
        this._settings[container.id] = null;
        var wrapper = new this._wrapperClass(svg, container);
        $.data(container, PROP_NAME, wrapper);
         ......
    },
 
可见在IE情况下并不会设置这个值,那么什么时候设置呢?registSVG方法如下:

    _registerSVG: function() {
        for (var i = 0; i < document.embeds.length; i++) { // Check all
            var container = document.embeds[i].parentNode;
            if (!$(container).hasClass($.svg.markerClassName) || // Not SVG
                $.data(container, PROP_NAME)) { // Already done
                continue;
            }
            var svg = null;
            try {
                svg = document.embeds[i].getSVGDocument();
            }
            catch(e) {
                setTimeout($.svg._registerSVG, 250); // Renesis takes longer to load
                return;
            }
            ......
        }
    },
 
奇怪的是并没有函数调用registerSVG(还没搞懂),不过也可以看出对IE来说设置值需要一定的时间,所以之前的代码马上执行svg('get')操作得不到正确值!
所以需要将svg();和svg('get');方法分开执行,或设置一段等待时间!

2009年9月15日星期二

[Bug-fixed]jQuery-SVG插件的使用

jQuery-SVG插件:http://keith-wood.name/svg.html

用于处理SVG文档,很方便。不过今天搞了一天一直无法正常显示SVG图片。

最后发现原因居然是:将SVG标签附加到一个<div>标签的时候必须要设置<div>的width和height,否则无法正常显示!!!

但是作者居然没有说明这个注意点,导致花了我一天最后排除所有可能的错误之后才发现这个问题!不过也因此对jQuery更了解了(看了一点源码,O(∩_∩)O哈哈~)。

2009年9月13日星期日

[转]JQuery的三个问答和如何编写自己的JQuery

三个问答:
1) 问:为什么$(selector)之后,返回的是jQuery对象?
答:从jQuery的源代码中,我们可以知道:var $ = jQuery.因此当我们$(selector)操作时,其实就是jQuery(selector),创建的是一个jQuery对象.当然正确的写法应该是这样的:var jq = new $(selector);而jQuery使用了一个小技巧在外部避免了new,在jquery方法内部:if ( window == this ) return new jQuery(selector);
2) 问:为什么创建一个jQuery对象之后,我们可以这样写$(selector).each(function(index){…});进行遍历操作呢?
答: 其实jQuery(selector)方法调用时,在jQuery(selector)方法内部,最后返回的是一个数组:return this.setArray(a);而each方法体内部是一个for循环,在循环体内是这样调用的:method.call(this[i],i).
3) 问:为什么jQuery能做到jQuery对象属性/方法/事件的插件式扩展?
答: 如果您有一些javasciprt的面向对象方面的知识,就会知道,jQuery.prototype原型对象上的扩展属性/方法和事件,将会给 jQuery的对象\”扩展”.基于这一点,jQuery是这样写的:jQuery.fn = jQuery.prototype.所以,当我们扩展一个插件功能时,如下:
 
jQuery.fn.check = function() {
  return this.each(function() {
    this.checked = true;
  });
};

其实就是:

jQuery.prototype.check = function() {
  return this.each(function() {
    this.checked = true;
  });
};
综上所述,jQuery给我们带来了一个简洁方便的编码模型(1>创建jQuery对象;2>直接使用jQuery对象的属性/方法/事件),一个强悍的dom元素查找器($),插件式编程接口(jQuery.fn),以及插件初始化的”配置”对象思想.

附:实现自己的jQuery

//实现自己的MyQuery框架
var MyQuery = function(selector){
    if ( window == this ) return new MyQuery(selector);
    //这里只实现dom类型的简单查找,嘿嘿
    var doms = document.getElementsByTagName(selector);
    var arr = [];
    for(var i=0; i<doms .length; i++){
        arr.push(doms.item(i));
    }
    return this.setArray(arr);
}
MyQuery.prototype.setArray = function( arr ) {
        this.length = 0;
        [].push.apply( this, arr );
        return this;
}
MyQuery.fn = MyQuery.prototype;
var $ = MyQuery;

//插件扩展1)each
MyQuery.fn.each = function(method){
    for(var i=0,l=this.length; i<l; i++){
        method.call(this[i],i);
    }
}
//插件扩展2)show
MyQuery.fn.show = function(){
    this.each(function(i){
        alert(i+“:“+this.id+“:“+this.innerHTML);
    });
}
//debugger
$(“div“).show();

[note]面向对象的Javascript:函数重载和类型检查

其它面向对象的语言(比如Java)的一种共有的特性是“重载”函数的能力:传给它们不同数目或类型的参数,函数将执行不同操作。虽然这种能力在JavaScript中不是直接可用的,一些工具的提供使得这种探求完全成为可能。
  在JavaScript的每一个函数里存在一个上下文相关的名为arguments的变量,它的行为类似于一个伪数组,包含了传给函数的所有参数。参数不是一真正的数组(意味着你不能修改它,或者调用push()方法增加新的项),但是你可以以数组的形式访问它,而且它也的确有一个length属性。程序 2-5中有两个示例。

  程序2-5. JavaScript中函数重载的两个示例
 
//一个简单的用来发送消息的函数 function sendMessage( msg, obj ) { //如果同时提供了一个消息和一个对象 if ( arguments.length == 2 ) //就将消息发给该对象 obj.handleMsg( msg ); //否则,刚假定只有消息被提供 else //于是显示该消息 alert( msg ); } //调用函数,带一个参数 – 用警告框显示消息 sendMessage( "Hello, World!" ); //或者,我们也可以传入我们自己的对象用 //一种不同方式来显示信息 sendMessage( "How are you?", { handleMsg: function( msg ) { alert( "This is a custom message: " + msg ); } }); //一个使用任意数目参数创建一个数组的函数 function makeArray() { //临时数组 var arr = []; //遍历提交的每一个参数 for ( var i = 0; i < arguments.length; i++ ) { arr.push( arguments[i] ); } //返回结果数组 return arr; }
  另外,存在另一种断定传递给一个函数的参数数目的方法。这种特殊的方法多用了一点点技巧:我们利用了传递过来的任何参数值不可能为undefined这一事实。程序2-6展示一了个简单的函数用来显示一条错误消息,如果没有传给它,则提供一条缺省消息。

  程序2-6: 显示错误消息和缺省消息
 
function displayError( msg ) { //检查确保msg不是undefined if ( typeof msg == 'undefined' ) { //如果是,则设置缺省消息 msg = "An error occurred."; } //显示消息 alert( msg ); }
  typeof语句的使用引入了类型检查。因为JavaScript(目前)是一种动态类型语言,使得这个话题格外有用而重要的话题。有许多种方法检查变量的类型;我们将探究两种特别有用的。
  第一种检查对象类型的方式是使用显式的typeof操作符。这种有用的方法给我们一个字符串名称,代表变量内容的类型。这将是一种完美的方案,除非变量的类型数组或自定义的对象如user(这时它总返回"ojbect",导致各种对象难以区分)。
  这种方法的示例见程序2-7

  程序2-7. 使用typeof决定对象类型的示例
//检查我们的数字是否其实是一个字符串 if ( typeof num == "string" ) //如果是,则将它解析成数字     num = parseInt( num ); //检查我们的数组是否其实是一个字符串 if ( typeof arr == "string" ) //如果是,则用逗号分割该字符串,构造出一个数组     arr = arr.split(",");
 
检查对象类型的第二种方式是参考所有JavaScript对象所共有的一个称为constructor的属性。该属性是对一个最初用来构造此对象的函数的引用。该方法的示例见程序2-8。

  程序2-8. 使用constructor属性决定对象类型的示例
//检查我们的数字是否其实是一个字符串 if ( num.constructor == String ) //如果是,则将它解析成数字     num = parseInt( num ); //检查我们的字符串是否其实是一个数组 if ( str.constructor == Array ) //如果是,则用逗号连接该数组,得到一个字符串     str = str.join(',');
 
程序2-9. 一个可用来严格维护全部传入函数的参数的函数
 
//依据参数列表来严格地检查一个变量列表的类型 function strict( types, args ) { //确保参数的数目和类型核匹配 if ( types.length != args.length ) { //如果长度不匹配,则抛出异常 throw "Invalid number of arguments. Expected " + types.length + ", received " + args.length + " instead."; } //遍历每一个参数,检查基类型 for ( var i = 0; i < args.length; i++ ) { //如JavaScript某一项类型不匹配,则抛出异常 if ( args[i].constructor != types[i] ) { throw "Invalid argument type. Expected " + types[i].name +", received " + args[i].constructor.name + " instead."; } } } //用来打印出用户列表的一个简单函数 function userList( prefix, num, users ) { //确保prefix是一个字符串,num是一个数字, //且user是一个数组 strict( [ String, Number, Array ], arguments ); //循环处理num个用户 for ( var i = 0; i < num; i++ ) { //显示一个用户的信息 print( prefix + ": " + users[i] );
 
  变量类型检查和参数长度校验本身是很简单的概念,但是可用来实现复杂的方法,给开发者和你的代码的使用者提供更好的体验。接下来,我们将探讨JavaScript中的作用域以及怎么更好的控制它。

[转]Android 手机全列表(包括 Motorola CLIQ)

CLIQ
Galaxy
Tattoo
Hero
Magic
G1
制造商 Motorola Samsung HTC HTC HTC HTC
键盘 横向 虚拟 虚拟 虚拟 虚拟 横向
界面 MOTOBLUR 基本
Sense UI Sense UI 基本 基本
处理器 528MHz MSM7201A 528MHz ARM11 528MHz MSM7225 528MHz MSM7201A 528MHz MSM7201A 528MHz MSM7201A
屏幕 3.1 � 320 X 480
3.2 � 320 x 480 2.8 � 240 x 320 3.2 � 320 x 480 3.2 � 320 x 480 3.2 � 320 x 480
耳机孔 3.5mm 3.5mm 3.5mm 3.5mm ExtUSB ExtUSB
触控屏幕 电容式 电容式 电阻式 电容式 电容式 电容式
视频镜头
500万自动对焦 500万 + 闪灯
320万 500万自动对焦 320万自动对焦 320万自动对焦
蓝芽 2.0 2.1 2.0 2.0 2.0 2.0
Exchange ActiveSync ActiveSync -- ActiveSync 视乎系统 视乎系统
内存 256MB, microSD 8GB, microSD 512MB, microSD 512MB, microSD 512MB, microSD 256MB, microSD
电池 1400mAh 1500mAh 1100mAh 1350 mAh 1340 mAh 1150 mAh
重量 163g 114g 113g 135g 116g 158g


加上 Motorola CLIQ,已知的 Android 系统的手机包括:G1、HTC Magic、Samsung Galaxy、HTC Hero、HTC Tattoo 及 Motorola CLIQ,共六部。其中以 HTC 最积极,占了四部。

依这个手机列表来看,六支 Android 手机的规格差别不算太大,分别主要在实体键盘、3.5mm 耳机孔 及 视像镜头。除了 HTC Tattoo 屏幕分辨率为 240 X 320 外,其它型号分辨率均具备 320 X 480。(各厂商推出的 Android 手机大同小异,规格战没什么看头,主战场应该是手机软件与按键设计吧!)

[转]地图投影及相关概念

<<<这是本人工作生涯接到的第一个任务,说实话因为涉及到不同的专业的知识,稍微有点棘手,不过没事比起毕业设计这是小菜一碟,这里记下一些学习的知识>>>

    1、椭球体

    GIS中的坐标系定义由基准面和地图投影两组参数确定,而基准面的定义则由特定椭球体及其对应的转换参数确定。

    基准面是利用特定椭球体对特定地区地球表面的逼近,因此每个国家或地区均有各自的基准面。基准面是在椭球体基础上建立的,椭球体可以对应多个基准面,而基准面只一个椭球体。

    椭球体的几何定义:

    O是椭球中心,NS为旋转轴,a为长半轴,b为短半轴。

    子午圈:包含旋转轴的平面与椭球面相截所得的椭圆。

    纬圈:垂直于旋转轴的平面与椭球面相截所得的圆,也叫平行圈。

    赤道:通过椭球中心的平行圈。

    基本几何参数:

    椭圆的扁率   
    椭圆的第一偏心率   
    椭圆的第二偏心率 

    其中a、b称为长度元素;扁率α反映了椭球体的扁平程度。偏心率e和e’是子午椭圆的焦点离开中心的距离与椭圆半径之比,它们也反映椭球体的扁平程度,偏心率愈大,椭球愈扁。

    套用不同的椭球体,同一个地点会测量到不同的经纬度。下面是几种常见的椭球体及参数列表。

    几种常见的椭球体参数值

    2、地图投影

    地球是一个球体,球面上的位置,是以经纬度来表示,我们把它称为“球面坐标系�”或“地理坐标系�”。在球面上计算角度距离十分麻烦,而且地图是印刷在平面纸张上,要将球面上的物体画到�上,就必须展平,这种将球面转化为平面的过程,称为“投影”。
经由投影的过程,把球面坐标换算为平面直角坐标,便于印刷与计算角度与距离。由于球面�法百分之百展为平面而不变形,所以除了地球仪外,所有地图都有某些程度的变形,有些可保持面积不变,有些可保持方位不变,视其用途而定。

    目前国际间普遍采用的一种投影,是即横轴墨卡托投影(Transverse Mecator Projection),又称为高斯-克吕格投影(Gauss-Kruger Projection),在小范围内保持形状不变,对于各种应用较为方便。我们可以想象成将一个圆柱体�躺,套在地球外面,再将地表投影到这个圆柱上,然后将圆柱体展开成平面。圆柱与地球沿南北经线方向相切,我们将这条切线称为“中央经线”。

    在中央经线上,投影面与地球完全密合,因此图形没有变形;由中央经线往�西两侧延伸,地表图形会被逐渐放大,变形也会越来越严重。

    为了保持投影精度在可接受范围内,每次只能取中央经线两侧附近地区来用,因此必须切割为许多投影带。就像将地球沿南北子午线方向,如切西瓜一般,切割为若干带状,再展成平面。目前世界各国军用地图所采用之 UTM 坐标系� (Universal Transverse Mecator Projection System),即为横轴投影的一种。是将地球沿子午线方向,每隔 6 度切割为一带,全球共切割为 60 个投影带。

     地图投影几何分类主要包括:

    结合变形性质和几何投影,投影分类包括:

    3、GIS中地图投影的定义

    我国的基本比例尺地形图(1:5千,1:1万,1:2.5万,1:5万,1:10万,1:25万,1:50万,1:100万)中,大于等于50万的均采用高斯-克吕格投影(Gauss-Kruger);小于50万的地形图采用正轴等角割园锥投影,又叫兰勃特投影(Lambert Conformal Conic);海上小于50万的地形图多用正轴等角园柱投影,又叫墨卡托投影(Mercator),我国的GIS系统中应该采用与我国基本比例尺地形图系列一致的地图投影系统。

    相应高斯-克吕格投影、兰勃特投影、墨卡托投影需要定义的坐标系参数序列如下: 
高斯-克吕格:投影代号(Type),基准面(Datum),单位(Unit),中央经度(OriginLongitude),原点纬度(OriginLatitude), 比例系数(ScaleFactor),东伪偏移(FalseEasting),北纬偏移(FalseNorthing)
兰勃特:投影代号(Type),基准面(Datum),单位(Unit),中央经度(OriginLongitude),原点纬度 (OriginLatitude),标准纬度1(StandardParallelOne),标准纬度2(StandardParallelTwo),东伪偏移(FalseEasting),北纬偏移(FalseNorthing)
墨卡托:投影代号(Type),基准面(Datum),单位(Unit), 原点经度(OriginLongitude),原点纬度(OriginLatitude), 标准纬度(StandardParallelOne)

    在城市GIS系统中均采用6度或3度分带的高斯-克吕格投影,因为一般城建坐标采用的是6度或3度分带的高斯-克吕格投影坐标。高斯-克吕格投影以6度或 3度分带,每一个分带构成一个独立的平面直角坐标网,投影带中央经线投影后的直线为X轴(纵轴,纬度方向),赤道投影后为Y轴(横轴,经度方向),为了防止经度方向的坐标出现负值,规定每带的中央经线西移500公里,即东伪偏移值为500公里,由于高斯-克吕格投影每一个投影带的坐标都是对本带坐标原点的相对值,所以各带的坐标完全相同,因此规定在横轴坐标前加上带号,如(4231898,21655933)其中21即为带号,同样所定义的东伪偏移值也需要加上带号,如21带的东伪偏移值为21500000米。
假如你的工作区位于21带,即经度在120度至126度范围,该带的中央经度为123度,采用Pulkovo 1942基准面,那么定义6度分带的高斯-克吕格投影坐标系参数为:(8,1001,7,123,0,1,21500000,0)。

    4、大地坐标系

    有了椭球体以及地图投影,坐标系就能确定下来了。北京54和西安80是我们使用最多的坐标系。我们通常称谓的北京54坐标系、西安80坐标系实际上使用的是我国的两个大地基准面北京54基准面和西安80基准面。我国参照前苏联从1953年起采用克拉索夫斯基(Krassovsky)椭球体建立了我国的北京 54坐标系,1978年采用国际大地测量协会推荐的1975地球椭球体建立了我国新的大地坐标系——西安80坐标系,目前大地测量基本上仍以北京54坐标系作为参照,北京54与西安80坐标之间的转换可查阅国家测绘局公布的对照表。 WGS-84坐标系采用WGS1984基准面及WGS84椭球体,它是一地心坐标系,即以地心作为椭球体中心,目前GPS测量数据多以WGS1984为基准。

    北京54坐标系

    北京54坐标系为参心大地坐标系,大地上的一点可用经度L54、纬度M54和大地高H54定位,它是以格拉索夫斯基椭球为基础,经局部平差后产生的坐标系,与苏联1942年建立的以普尔科夫天文台为原点的大地坐标系统相联系,相应的椭球为克拉索夫斯基椭球。到20世纪80年代初,我国已基本完成了天文大地测量,经计算表明,54坐标系统普遍低于我国的大地水准面,平均误差为29米左右。

    西安80坐标系

    西安80是为了进行全国天文大地网整体平差而建立的。根据椭球定位的基本原理,在建立西安80坐标系时有以下先决条件:

    (1)大地原点在我国中部,具体地点是陕西省径阳县永乐镇;

    (2)西安80坐标系是参心坐标系,椭球短轴Z轴平行于地球质心指向地极原点方向,大地起始子午面平行于格林尼治平均天文台子午面;X轴在大地起始子午面内与 Z轴垂直指向经度 0方向;Y轴与 Z、X轴成右手坐标系;

    (3)椭球参数采用IUG 1975年大会推荐的参数,因而可得西安80椭球两个最常用的几何参数为:

    长轴:6378140±5(m);

    扁率:1:298.257

  椭球定位时按我国范围内高程异常值平方和最小为原则求解参数。

  (4)多点定位;

  (5)大地高程以1956年青岛验潮站求出的黄海平均水面为基准。

    WGS-84坐标系

    WGS-84(World Geodetic System,1984年)是美国国防部研制确定的大地坐标系,其坐标系的几何定义是:原点在地球质心,z轴指向 BIH 1984.0定义的协议地球极(CTP)方向,X轴指向 BIH 1984.0 的零子午面和 CTP赤道的交点。Y轴与 Z、X轴构成右手坐标系(如图所示)。

    WGs-84椭球及有关常数:

    对应于 WGS-8大地坐标系有一个WGS-84椭球,其常数采用 IUGG第 17届大会大地测量常数的推荐值。

    WGS-84椭球的几何常数:

    长半轴: 6378137± 2(m)

    扁率:1 / 298.257223563

    地球引力常数(含大气层)GM=3986005

    正常化二阶带谐系数C2.0= -484.16685×10-6

    地球自转角速度 w= 7292115×10-11 rads -1

    主要几何和物理常数

    短半径 b= 6356752.3142 m

    扁率 f=1/298.257223563

    第一偏心率平方 e2= 0.00669437999013

    第二偏心率平方 e’2 =0.006739496742227

    �球正常重力位 U0= 62636860.8497m2s-2

    赤道正常重力 r0= 9.9703267714ms-2


http://gps.eefocus.com/html/09-07/4868716090725Nqu3.html

2009年9月11日星期五

[bug-fixed]今天遇到的http的GET和PUT方法与JavaServlet的一些问题

http的Get方法是只有报头,也就是无法发送内容的。我今天也犯了这个错误。估计DELETE方法也发不了内容(猜测而已,没实践过)。

另外http的Put方法虽然可以发送参数,但是即使发送的形式是"键=值&键=值",也不能像POST方法那样用servlet函数request.getParameter("键");得到值。

这两错误让我郁闷很久...

[note使用Javascript域

在开发一个Javascript库的时候,因为js只有全局和局部变量,为了不引起冲突,变量的命名是很重要的。如何让自己的变量的命名与其他的库或开发者的命名不冲突呢?

最好的方法就是使用“域”!

域是一个比较形象的说法,其实并并不是js里面的一个特殊关键字之类的东西。相反他是使用类实现的。

如下是一个类的代码:
function class () {
      ...
}

同样一个匿名的类的写法如下:
function () {
      ...
}
 
这样声明了一个名为class的类。调用的时候就如下:
var c = new class();

连在一起就是如下代码:
window.className = (function() {
      ...
}) ();

这样实际上就是一个全局域className.

这样我们在这域中设置变量,函数甚至是类都不大可能会与开发者的命名冲突。

另外还有另一种使用域的方法:
这是jQuery的形式:
(function() {
   var _jQuery = window.jQuery;
   var _$ = window.$;
   var jQuery = window.jQuery = window.$ = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context );
   };
......
......
})();
这样定义的变量属于一个匿名的域里面而不会产生冲突。
jQuery的插件也为了避免$产生冲突定义了如下代码:
(function($) {
......
})(jQuery);
这样吧jQuery传入函数,得到$的表示,很巧妙!


PS:Javascript真的是我用过的最巧妙的语言,所以也比起一般的语言要用的融会贯通的话真的难一点

2009年9月10日星期四

[note]SVG基本教程

SVG基本图形

  SVG内建图形有:

  • 长方形(RECTANGLE)
  • 圆形(CIRCLE)
  • 椭圆形(ellipse)
  • 直线(line)
  • 多边形(polygon)
  • 连续线(polyline)

图形着色

  • Fill :设定图形内部着色
  • Fill-opacity:设定图形内部透明度
  • Stroke:设定图形轮廓着色
  • Stroke-width:设定图形轮廓宽度

<rect>元素

  • X:起始点x轴座标
  • Y:起始点y轴座标
  • Width:长方形宽度
  • Height:长方形高度
  • rx:圆角方形x半径
  • ry:圆角方形y半径

图2 SVG <RECT>元素

图2 SVG <RECT>元素

  部份代码:

<rect x="10" y="10" width="50" height="50" />
<rect x="10" y="150" rx="5" ry="5" width="50" height="50" fill="green" stroke="red"/>

  解说:以上两个图形的差别是在设定rx和ry的有无,绿色边角有圆弧度!

<circle>元素

  • Cx:圆心之x轴座标
  • Cy:圆心之y轴座标
  • R:圆之半径

图3 SVG <circle>元素

图3 SVG <circle>元素

  部份代码:

<circle cx="30" cy="30" r="25" />
<circle cx="150" cy="90" r="25" fill="green" stroke="red" stroke-width="4" stroke-opacity="0.5"/>

  解说:此两圆差别在于stroke和stroke_width的设定 第二个图有设定stroke=red 他的轮廓有红色包围

<ellipse>元素

  • Cx:椭圆形圆心x轴座标
  • Cy:椭圆形圆心y轴座标
  • Rx:椭圆形x轴之半径
  • Ry:椭圆形y轴之半径

图4 SVG <ellipse>元素

图4 SVG <ellipse>元素

  部份代码:

<ellipse cx="30" cy="30" rx="25" ry="15" />
<ellipse cx="210" cy="30" rx="25" ry="15" fill="none" stroke="red" />

  解说:两图的差别在第二个fill的属性有设定填满为none表示没有无填满,而第一个图没有设定的话,他的default 值为填满!

<line>元素

  • X1:起始点x轴座标。
  • y1:起始点y轴座标。
  • X2:结束点x轴座标。
  • y2:结束点y轴座标。

图5 SVG <line>元素

图5 SVG <line>元素

  部份代码:

<line x1="10" y1="10" x2="50" y2="50" />
<line x1="60" y1="10" x2="110" y2="50" stroke="green"/>

  解说:两点成一直线,所以只要设定两点x1 y1 x2 y2就会自动连成一直线

<ploygon>元素

图6 SVG <ploygon>元素

图6 SVG <ploygon>元素

  解说:跟直线的性质大略相同,不过可以设多点,他会自动连接起来,自动连成一个多边形!

<svg>元素

  <svg>元素用来产生一块画布,让SVG图形元素能被描绘在上面,它是SVG文件的根元素,<svg>~</svg>元素之间所包含的SVG被称为SVG文件;在资源情况下,可以被嵌入行内作为XML父文件的里的一个片段。SVG文件必须遵照在XML的名称空间推荐,宣告名称空间以便所有SVG元素能被辨认属于这个SVG名称空间。

<title>及<desc>元素

  用来描述文字字串,常与群组结构元素或图形元素连用以提供相关资讯。<desc>及<title>元素的内容不会被显示画布上,相当于是注解功能。

<g>元素

   是一种用来群组相关图形元素在一起的容器元素,群组元素被视为单独物件,可以使用属性id为群组命名以便做为动画及再使用物件。

图7 SVG <g>元素

图7 SVG <g>元素

  部份代码:

 <desc>圆群组</desc>
  <g fill-opacity="0.7" stroke="black" stroke-width="0.1cm">
    <circle cx="6cm" cy="2cm" r="100" fill="red"
                    transform="translate(0,50)" />
    <circle cx="6cm" cy="2cm" r="100" fill="blue"
                    transform="translate(70,150)" />
    <circle cx="6cm" cy="2cm" r="100" fill="green"
                    transform="translate(-70,150)" />
  </g>

  下面是<g>元素代码示范

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="4in" height="3in" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<desc>Groups can nest
</desc>
<g>
<g>
<g>
</g>
</g>
</g>
</svg>

  <g>元素简言之,其实就相当于今日大家所使用的msn的群组功能,而<g>元素可以将相似的图形都归类在一起,属性id也相当于是群组的名称,以便日后要再被使用时可以被呼叫。如上例,就有三个子元素的circle构成的一个群组,而此群组的名称就称为g1。

  下图是SVG <g>元素实例,点击图片可以查看SVG文件。

图8 SVG <g>元素实例

图8 SVG <g>元素实例

<symbol>元素

  主要用途是为相同文件里,多次使用的图形模版画以增加文件结构性。

图9 SVG <symbol>元素

图9 SVG <symbol>元素

  以右图的箭头为例:

<svg>
<desc>定义箭头符号</desc>
  <symbol id="arrow" >
  <path d="M10 50 v -20 h50 v-25 l 40 45 M10 50 v 20 h50 v 25 l 40 -45 " />
  </symbol>
 <desc>symbol的使用方法</desc>
  <use x="0" y="20" xlink:href="#arrow" fill="green" stroke="red" fill-opacity="0.1"/>
</svg>

  补充一下说明此箭头的形成:参照上面范例的path,l是一个起点,10和50这两组数字分别代表X与Y的位置,而图形从此这做起。接着v但表垂直,-20是相对于M的位置而言,所以要往下20,接着h50是水平线往右移动50,再来v-25又是往下25,接着l 40 45,是画斜的连接到(40,45)的位置,这样就完成了一半,另外一半对称图形也是此类推即可完成。
 
  补充说明:

  • <symbol>元素与<g>元素的差别是:
  • <symbol>元素本身不被显示,只有<symbol>元素的例证才会被显示。
  • <symbol>元素的有viewBox和preserveAspectRatio属性允许
  • <symbol>做适合缩放以符合由<use>元素定义长方形的观测阜。

<defs>元素

  <defs>元素的内容模式和<g>元素一样,因此,任何使用在<g>元素容器里的子元素,同样的也可以使用在<defs>元素里,反之亦然,<defs>元素的内容不会直接被显示。而<defs>元素是针对被参考元素的容器元素,为了文件的可读性及可存取性而设置的,SVG规范建议尽可能将被参考的元素定义在<defs>元素中。

图10 SVG <defs>元素

图10 SVG <defs>元素

<desc>定义参考字串及文字路径</desc>
<defs>
 <text id="refText">SVG</text>
 <path id="pathText" d="M40 100 a 50 50 0 0 1 100 0 m 0 0 a 50 50 0 0 1 -100 0 "  />
</defs>
 <text fill="green" font-size="20" letter-spacing="4">
  <textPath xlink:href="#pathText">text reference to a path
  </textPath>
 </text>

<image>元素

  可以将一个完整个档案内容显示在当前使用者坐标系统所指定的长方形<image>元素能参考光栅图形影像档案,像是PNG、JPEG、MIME格式的档案。

<image x="40" y="40" width="100px" height="100px" xlink:href="/./graphics/123123.gif" />

  下图是SVG <image>元素实例,点击图片可以查看SVG文件。

图11 SVG <image>元素实例

图11 SVG <image>元素实例

SVG 引用SMIL动画元素

  • <animate>   对单一随时间变化的属性做动画
  • <set> 非数值属性和性质的动画
  • <animateMotion>  让一个元素沿着路径运动
  • <animateColor>  设定随时改变的颜色转换

SVG 延伸SMIL动画元素

  <animateTransform> 允许动画控制平移、缩放、旋转、倾斜
  Path属性 允许path属性设定到animateMotion元素
  <mpath>  SVG允许一个animateMotion元素包含一个参考到SVGpath元素,当作运动路径定义的mpath子元素
  keyPoint属性 SVG增加keyPoint属性,对animateotion元素运动路径动画精确的速度控制
  rotate属性 SVG增加rotate属性,提供animateMotion元素控制物件在她的X轴相同方向或相反方向自动旋转,当为运动路径的方向切线速度

SVG的动态图片1

  之前的效果

图12 SVG 动态图片1之前的效果

图12 SVG 动态图片1之前的效果

 
  之后的效果

图13 SVG 动态图片1之后的效果

图13 SVG 动态图片1之后的效果

<animate attributeName="width" form=“400" to=“800" begin="0s" dur="10s" repeatCount="1" fill="freeze"/>

  这个动态图片是一张图片分割成两边,从中间向两旁延伸,以上的文件是属于右边的延伸,form=“400" to=“800”表示从图片横向座标的400到800做延伸,左边则是form=“400" to=“0”

  例图:

图14 SVG 动态图片1历边的效果

图14 SVG 动态图片1右边的效果

SVG的动态图片2

  这个动态图片是利用begin元素设定不同的触发条件来控制图片起跑的顺序

  例图:

图15 SVG 动态图片2效果

图15 SVG 动态图片2效果

<animate id="r1X" xlink:href="#r1" attributeName="x" attributeType="XML" from="0" to="600" begin="r1.click"  dur="2s" repeatCount="1" />

  这段的文件,控制第一张图片的起跑触发是begin="r1.click",我们将它设定为当我点下滑鼠才会起跑

  另外四张图,都有不同的触发条件

  • begin=“r1.click“  点一下起跑
  • begin=“accessKey(S)“ 按下S起跑
  • begin=“0s;r5X.end“ 一开始起跑和r5结束起跑
  • begin=“r3X.repeat(2)“ r3跑两次后起跑
  • begin=“r4X.end+1s“ r4结束后一秒起跑

  好了,本篇文章讲到这里就结束了,对于SVG入门文章大家可以可以参见更详细的内容:“新一代Web设计及互动媒体的革”“什么是SVG(可升级矢量图形)”。该两篇文章主要是让大家了解什么是SVG,以及SVG的优点等知识。


(THE END)

[note]SVG格式图形显示的坐标系统规则

SVG的坐标系统

  所有的渲染都是在某个矩形(视口,viewport)中发生。

  SVG的客户端解释程序获得一些信息后(设备像素数所定义的高度值、宽度值,一个像素所代表的具体尺寸这样三个参数),首先初始化视口,建立以像素为单位的视口坐标系,接着建立用户坐标系,使两者一致,也就是使用户坐标系中的一个单位(如1m或1cm)等于视口坐标系中的一个像素。

  渲染SVG文件时,如果SVG文件的长度值与坐标值等没有规定单位,则缺省地采用用户坐标系的单位,也就是使用像素作为度量单位。如果有特定的单位,如mm,cm等,则需要经过换算,将尺寸转换为用户坐标值。这也是客户端解释程序时,需要第三个参数的原因。

  还可以定义自己的坐标系。方式是在一段SVG文本中定义一种叫做变换(transformation)的格式,其含义类似于解析几何中的坐标转换和映射规则。变换的格式中说明了此变换所作用的对象应该使用设么方式进行平移、缩放、旋转、歪斜等。变换提供了一种整体的方式,用它可对一个或一组图像对象进行变换,改变其比例、位置、形状等,以达到使用自定义坐标系的目的。

初始化视口和坐标系统

  客户端渲染SVG图像时,需要和具体设备或上层用户程序进行交互通讯,以确定视口。有时SVG只作为对象嵌入网页中。这个网页本身可能有一些渲染视口的一些属性参数(如位置),而<svg>标记内,又有自己定义的高与宽参数,于是客户端尽量使用两者信息来创建合适的位置和尺寸的初始视口。

  <svg>的width和height属性用于标记SVG图像渲染得初始视口大小。如果没有带单位,则使用用户坐标系的长度单位:像素。

  用户坐标系:原点在视口左上角,x轴正向朝右,y轴正向朝下,文字从上到下从左到右。如果不进行坐标变换,一切都以初始坐标系为准。

  默认情况下,视口坐标系和用户坐标系一致,度量单位也一致(用户坐标系中的一个缺省单位代表视口坐标系中一个像素)。

情况有变:都是因为"viewBox"属性

  用户的初始视口和初始坐标系是一致的。长度的缺省度量单位为像素。但如果<svg>元素中出现"ViewBox"属性,那么情况就不同了。"viewBox"的作用是规定视口的坐标范围,范围重新定义后,缺省的坐标度量单位也会改变。
<svg width="4cm" height="4cm" viewBox="0 0 400 400">

  意思是SVG文档的视口大小为4cm,坐标范围被标记为(0 0 400 400)。合理的解释可能是:视口为400乘400像素,而缺省的用户坐标系的度量单位变成0.01cm,而不是具体的一个像素。即相当于对整个SVG图像进行坐标变换。即可以理解为显示屏上1像素代表0.01cm。

  如果使用了viewBox,用保持viewBox值不变而修改width和height属性,整幅图像会随之放大或缩小。这是单纯使用<svg>的width和height所达不到的。

  地图……本身就有着太多坐标纠葛的东西,要用SVG来表达,问题多多。这个世界太复杂,我也太贪心了。

  最后,为进一步了解SVG的坐标系统及其坐标规则,你还可以阅读"SVG坐标系统与SVG坐标变换"一文,该文是IBM Developerworks会员区的内容,本文通过详细的文字介绍及实例介绍了SVG的坐标系统,以及SVG的坐标变换内容。

2009年9月8日星期二

看来坚持在Blogger战线的人就我一个了

自从Blogger被封后,好友都不再更新了,就我坚持用gmail发新文章了。

[转]优化js脚本性能的方法

<<<--------------------------------原文有点乱,在这里稍事修改,贴出来。予以自勉-------------------------------->>>
随着网络的发展,网速和机器速度的提高,越来越多的网站用到了丰富客户端技术。而现在Ajax则是最为流行的一种方式。JavaScript是一种解释型 语言,所以能无法达到和C/Java之类的水平,限制了它能在客户端所做的事情,为了能改进他的性能,我想基于我以前给JavaScript做过的很多测 试来谈谈自己的经验,希望能帮助大家改进自己的JavaScript脚本性能。

语言层次方面

1. 循环
循环是很常用的一个控制结构,大部分东西要依靠它来完成,在JavaScript中,我们可以使用 for(;;),while(),for(in)三种循环,事实上,这三种循环中for(in)的效率极差,因为他需要查询散列键,只要可以就应该尽量少 用。for(;;)和while循环的性能应该说基本(平时使用时)等价。 而事实上,如何使用这两个循环,则有很大讲究。我在测试中有些很有意思的情况。

最后得出的结论是:
  • 如果是循环变量递增或递减,不要单独对 循环变量赋值,应该在它最后一次读取的时候使用嵌套的++或--操作符。
  • 如果要与数组的长度作比较,应该事先把数组的length属性放入一个局部变量 中,减少查询次数。举例,假设arr是一个数组,最佳的遍历元素方式为:for(var i=0, len = arr.length;i0;i--){...}局部变量和全局变量
  • 局部变量的速度要比全局变量的访问速度更快,因为全局变量其实是全局对象的成员,而局部变量是放在函数的栈当中的。
  • 不使用Eval,使用eval相当于在运行时再次调用解释引擎对内容进行运行,需要消耗大量时间。这时候使用JavaScript所支持的闭包可以实现函数模版 (关于闭包的内容请参考函数式编程的有关内容)
  • 减少对象查找因为JavaScript的解释性,所以a.b.c.d.e,需要进行至少4次查询操作,先检 查a再检查a中的b,再检查b中的c,如此往下。所以如果这样的表达式重复出现,只要可能,应该尽量少出现这样的表达式,可以利用局部变量,把它放入一个 临时的地方进行查询。这一点可以和循环结合起来,因为我们常常要根据字符串、数组的长度进行循环,而通常这个长度是不变的,比如每次查询 a.length,就要额外进行一个操作,而预先把varlen=a.length,则就少了一次查询。
  • 字符串连接 ,如果是追加字符串,最好使用s+=anotherStr操作,而不是要使用s=s+anotherStr。如果要连接多个字符串,应该少使用+=,如s+=a;s+=b;s+=c;应该写成s+=a + b + c;而如果是收集字符串,比如多次对同一个字符串进行+=操作的话,最好使用一个缓存。怎么用呢?使用JavaScript数组来收集,最后使用join 方法连接起来,如下
         var buf = new Array();
         for(var i = 0; i < 100; i++) {
                buf.push(i.toString());
          }
          var all = buf.join("");

2. 类型转换
类型转换是大家常犯的错误,因为JavaScript是动态类型语言,你不能指定变量的类型。

  • 把数字转换成字符串,应用"" + 1,虽然看起来比较丑一点,但事实上这个效率是最高的,性能上来说: ("" + ) > String() > .toString() > new String() 这条其实和下面的直接量有点类似,尽量使用编译时就能使用的内部操作要比运行时使用的用户操作要快。 String()属于内部函数,所以速度很快,而.toString()要查询原型中的函数,所以速度逊色一些,new String()用于返回一个精确的副本 。
  • 浮点数转换成整型,这个更容易出错,很多人喜欢使用parseInt(),其实parseInt()是用于将字符串转换成数字,而不是浮点数 和整型之间的转换,我们应该使用Math.floor()或者Math.round()。另外,和第二节的对象查找中的问题不一样,Math是内部对象, 所以Math.floor()其实并没有多少查询方法和调用的时间,速度是最快的。
  • 对于自定义的对象,如果定义了toString()方法来进行类型转换的话,推荐显式调用toString(),因为内部的操作在尝试所有可能性之后,会尝试对象的toString()方法尝试能否转化为String,所以直接调用这个方法效率会更高使用直接量。其实这个影响倒比较小,可以忽略。什么叫使用直接量,比如,JavaScript支持使用[param,param,param,...]来直接 表达一个数组,以往我们都使用new Array(param,param,...),使用前者是引擎直接解释的,后者要调用一个Array内部构造器,所以要略微快一点点。同样,var foo = {}的方式也比var foo = new Object();快,var reg = /../;要比var reg=new RegExp()快。

3. 字符串遍历操作
对字符串进行循环操作,譬如替换、查找,应使用正则表达式,因为本身JavaScript的循环速度就比较慢,而正则表达式的操作是用C写成的语言的API,性能很好。

4. 高级对象
  • 自定义高级对象和Date、RegExp对象在构造时都会消耗大量时间。如果可以复用,应采用缓存的方式。
  • DOM相关插入HTML,很多人喜欢在JavaScript中使用document.write来给页面生成内容。事实上这样的效率较低,如果需要直接插入HTML,可以 找一个容器元素,比如指定一个div或者span,并设置他们的innerHTML来将自己的HTML代码插入到页面中。
  • 对象查询,使用[""]查询要比.items()更快,这和前面的减少对象查找的思路是一样的,调用.items()增加了一次查询和函数的调用。
  • 创建DOM节点,通常我们可能会使用字符串直接写HTML来创建节点,其实这样做无法保证代码的有效性
  • 字符串操作效率低,所以应该是用document.createElement()方法,而如果文档中存在现成的样板节点,应该是用cloneNode()方法,因为使用createElement()方法之后,你需要设置多次元素的属性,使用cloneNode()则可以减少属性的设置次数同样如果需要创建很多元素,应该先准备一个样板节点。
  • 定时器如果针对的是不断运行的代码,不应该使用setTimeout,而应该是用setInterval。setTimeout每次要重新设置一个定时器。

5.文件优化
文件优化也是一个很有效的手段,删除所有的空格和注释,把代码放入一行内,可以加快下载的速度,注意,是下载的速度而不是解析的速度,如果是本地,注释和空格并不会影响解释和执行速度。

6.总结 
本文总结了我在JavaScript编程中所找到的提高JavaScript运行性能的一些方法,其实这些经验都基于几条原则:

  • 直接拿手头现成的东西比较快,如局部变量比全局变量快,直接量比运行时构造对象快等等。
  • 尽可能少地减少执行次数,比如先缓存需要多次查询的。
  • 尽可能使用语言内置的功能,比如串链接。
  • 尽可能使用系统提供的API,因为这些API是编译好的二进制代码,执行效率很高
同时,一些基本的算法上的优化,同样可以用在JavaScript中,比如运算结构的调整,这里就不再赘述了。但是由于JavaScript是解释型的,一般不会在运行时对字节码进行优化,所以这些优化仍然是很重要的。

[转]拼装html字符串的最快方法

原文地址:Fastest way to build an HTML string

第一种:逐个字符串相加

var arr = ['item 1', 'item 2', 'item 3', ...],
list = '';

for (var i = 0, l = arr.length; i < l; i++) {
list += '<li>' + arr[i] + '';
}

list = '<ul>' + list + '</ul>';

这种最常见的,但是效率最低!代码逻辑相对来说复杂。

第二种:逐个 push 进数组

var arr = ['item 1', 'item 2', 'item 3', ...],
list = [];

for (var i = 0, l = arr.length; i < l; i++) {
list[list.length] = '<li>' + arr[i] + '';
}

list = '<ul>' + list.join('') + '</ul>';

比上一种方法稍微快一些,但还是不够好…

第三种:直接join()

var arr = ['item 1', 'item 2', 'item 3', ...];

var list = '<ul><li>' + arr.join('</li><li>') + '</li></ul>';

使用原生的方法(比如 join()),不管它后面是怎么实现的,一般都比其他方法快很多,而且代码非常简洁。

浏览器性能

每种方法是使用一个长度为 130 的数组来测试,其中每个元素的长度是多种多样的,防止浏览器对一定长度的字符串做特殊的优化;每种方法测试了 1000 次;下面的结果显示,执行完这 1000 次需要的时间:

2009-09-08_124126