【技術分享】很詳細的JS底層分析


1. 序言
現在學的東西很容易忘記,寫這篇文章的目的是能讓我在需要時快速找回當時的感覺.

入門學習和參考手冊建議翻閱JavaScript.The.Definitive.Guide.5th.Edition的附錄(有電子版).


2. 准備
設置服務器*.xml的MIME為text/xml ,Windows Xp自帶的IIS的設置如下圖 js_0000.png

Firefox上有許多插件是開發必備的,用法大家Google,我列一下名稱

FireBug

Web Developer Toolbar 
GreaseMonkey 和 XmlHttpRequestDebugging

Html Validator 
另外建議安裝一下DreamWaver和EditPlus. EditPlus中可以快速切換IE和Js腳本,快捷鍵Ctrl+B 強烈建議學習時便學邊調試

3. 如何嵌入網頁?

3.1. 寫在網頁中
<script type="text/javaScript">
//代碼
</script>

3.2. 在鏈接上使用偽協議
<a href="javascript:void window.open();">Open</a>


3.3. 使用獨立的js腳本
<script language="javascript" src="/js/dialog.js" />

4. 語言核心

4.1. 關於分號
javascript的分號是選加的,如果不加,javacript會在換行處自動加上分號.

但是,建議你不要省略分號,理由如下

加了分號的代碼可以用軟件壓縮,來節省帶寬(附帶效果是加密你的Js代碼:) )(Ajax基礎教程 上的理由) 
良好的編程習慣(Javascript權威指南 上的理由)

4.2. 輸出Html最簡單的方式
見例子1_1

doucment.write("Hello World");

4.3. alert : 彈出窗口,調試必備
見例子1_2

alert("彈出窗口,調試必備");

4.4. 命名規則
區分大小寫,開頭必須是字母或 $ 或 _


4.5. 基本類型

4.5.1. 字符串
使用Unicode字符,如

"test"

'name="zsp"' //雙引號可以放在單引號中,反之亦然

'You/'re right' //轉義字符,和C++的轉義相同

字符串的屬性

str="zsp007@gmail.com"

str.length
//字符串的長度

str.charAt(str.length-1)
//字符串的最后一個字符(注意,第一個字符的索引是0,和C++數組類似)

str.indexOf("@")
//第一個 @ 字符的位置

str.substring(str.lastIndexOf(".")+1,str.length);
//提取后綴"com",提取規則是左開右閉(就是包括左邊參數所代表的元素,而不包括右邊的)

str.toUpperCase();
//返回大寫形式

4.5.2. 十六進制
0xff //15*16+15=255 , 0x為十六進制前綴


4.5.3. 浮點
-3.14 6.02E-23 //6.02 X 10-23(10的負23次方)


4.5.4. 特殊常量
Infinity 無窮大 
Number.POSITIVE_INFINITY 正無窮大 
Number.NEGATIVE_INFINITY 負無窮大 
NaN 或 Number.NaN 非法的值 
Number.MAX_VALUE 可表示的最大值 
Number.MIN_VALUE 可表示的最接近0的值

4.5.5. 布爾值
true==1 false==0


4.5.6. 基於對象

4.5.6.1. 創建
方式1:

var o = new Object();
o.x=2.3;
o.y=-1.2;
方式2:

var o={x:2.3 , y:-1.2};
調用 ox //返回2.3

一個復雜點的例子 見例子1_3

var point={x:2.3,y:-1.2};
var side=4;
var square={
        upperLeft : {x:point.x , y:point.y},
        lowerRight : {x:(point.x + side) , y:(point.y+side)}
};

alert(square["upperLeft"]["x"]);//顯示2.3
備注:內建類型字串不是Object(),即用typeof得到的是"string",和"object"不等價,但在任何需要的地方他會自動轉化為一個String對象


4.5.6.2. 構造函數

function Rectangle(w,h)//構造函數.不要返回值,因為返回值會使this失效
{
        this.width=w;
        this.height=h;
}
var rect1=new Rectangle(2,4);//創建對象


4.5.6.3. 成員函數

function Rectangle_area(){return this.width * this.height;}//聲明函數

function Rectangle(w,h)
{
this.width=w;this.height=h;

this.area = Rectangle_area;//關聯函數為成員函數
}

var r=new Rectangle(3,2);
r.area();//返回6

4.5.6.4. 繼承
Javascript的類都自動繼承了原型對象 Object.prototype 
繼承的屬性為只讀的,既子類不可以給繼承的屬性賦值 
子類的同名屬性/函數將覆蓋父類的同名屬性/函數 
String和Date等內部類也有原型對象

//定義一個父類
function Complex(real , imaginary){
        this.x=real;
        this.y=imaginary;
}

//為父類添加一個方法,通過定義父類原型prototype的函數
//該方法同時覆蓋了Object.prototype中的同名函數
Complex.prototype.toString=function(){
        return this.x+"+"+this.y+"j";
}

//定義一個Complex函數,該函數不會被繼承(這時不要加this了)
Complex.magnitude=function()
{
        return Math.sqrt(x*x+y*y);      
}

//定義一個子類
function MoreComplex(real , imaginary){
        this.x=real;
        this.y=imaginary;
}

//繼承父類,注意這時MoreComplex的構造函數被父類的構造函數覆蓋
MoreComplex.prototype=new Complex(0,0);

//明確指定,使MoreComplex使用自己的構造函數
MoreComplex.prototype.constructor=MoreComplex;

//定義子類自己的函數
MoreComplex.prototype.swap=function(){
        var tmp=this.x;
        this.x=this.y;
        this.y=tmp;
}

a=new MoreComplex(11,33);

alert(a);//自動調用Complex.toString()
a.swap();
alert(a);

4.5.6.5. 公共基類的屬性
Object.prototype是所有類的公共基類

constructor屬性 構造器,由於構造函數確定了一個對象的類型,可以用如下代碼確定一個對象的類型 
if((typeof o=="object" )&& o.constructor == Date)//...........
 但不能保證constructor屬性總是存在,類的創建者可以指定一個對象來取代原型的構造器,而指定的對象可以沒有 constructor (PS:此句抄書,我看不懂)

toString() 返回一個字串,內容為對象的值或類型. 默認的toString對於對象返回

[object class]
//class為類名,如自定義對象為Object
//類似的還有Array,Function,Date,Math,Error,Window,Document,Form
由於可以重載toString.所以,如果你想明確的調用默認的toString來獲得類型信息,你可以這樣

Object.prototype.toString.apply(x);
toLocaleString() Object默認的toLocaleString返回值和toString相等;Array,Date,Number都綁定了自己的toLocaleString 
valueof() Object默認定valueof不執行任何轉換,Number和Boolean等有自定義的valueof(). 當你自定義了valueof時需要注意的是:valueOf()優先級比toString()高,所以,你常不得不明確的調用toString() 
hasOwnProperty() 
var o = new Object();
o.hasOwnProperty("undef"); //false:沒有定義該屬性
o.hasOwnProperty("toString"); //false:該屬性是繼承的

Math.hasOwnProperty("cos");//true:Math有cos屬性
 * propertylsEnumerable() 一個屬性如果可以由for...in循環枚舉出來就返回true,否則,返回false

var o = {x:1};
o.propertylsEnumerable("x");//true
o.propertylsEnumerable("y");//false,無該屬性
o.propertylsEnumerable("valueOF");//false,該屬性不可枚舉
isPrototypeOf() 調用該函數的對象如果是參數的原型,就返回true 
 var o=new Object();
 Object.prototype.isPrototypeOf(o);
 //true,o.constructor == Object

 Object.isPrototypeOf(o);//false
 o.isPrototypeOf(Object.prototype);//false

 Function.prototype.isPrototypeOF(Object);
 //true:Object.constructor == Function

4.5.7. 數組

4.5.7.1. 創建
方式1

var a = new Array();
a[0]=2;
a[1]="I'm a earthman ."
a[2]=true;
a[3]={x:1 , y:3}
方式2

var a=new Array(2,"I'm a earthman .",true,{x:1 , y:3});
var a2=new Array(10);//注意,這個10是表示a有10個未定義元素!(因為這時候只傳給Array一個參數)
方式3

var a=[2,"I'm a earthman .",true,{x:1 , y:3}];
var a2=[[1,2,3],[1,2,3]];//可以嵌套

var base=11;
var a3[base,base+1,base+2];//可以為變量

var a4=[1,,,,5];//有3個未定義的元素

4.5.7.2. 數組的函數
* join() 把所有的元素轉換為字串,參數作為分隔符(默認分隔符是 ,)

var a=[1,2,3];
a.join();//1,2,3
a.join(" : ");//1 : 2 : 3
* reverse() 對數組反向排序 * sort() 默認按照UTF-8碼的順序排序,可以傳一個參數,如果返回一個小於等於0的數,第1個參數出現在第2個參數前面,反之同理.

 function randOrd(){
return (Math.round(Math.random())-0.5);
}

anyArray = new Array('3','a','5','F','x','47');
anyArray.sort( randOrd );       //把數組亂序排列
* concat() 返回一個數組,包含了原數組和參數

anyArray = new Array(47,33);

anyArray.concat(8,99,88 );
//[47,33,8,99,88]

anyArray.concat([8,99],[88,53] );       
//[47,33,8,99,88,53],會自動把參數中數組拆包一層

anyArray.concat(2,[3,[4,5]]);   
//[47,33,2,3,[4,5]],拆包只拆一層
* slice() 返回一個數組的切片,返回規則如下

var a = [1,2,3,4,5]
a.slice(0,3); //返回a[0]至a[2],即[1,2,3]
a.slice(3);        //返回a[3]至結尾,即[4,5]
a.slice(1,-1);//返回a[1]至最后一個元素[2,3,4]
a.slice(-3,-2);//返回[3]
* splice() 可以刪除/添加原數組元素,同時返回刪除的值

var a = [1,2,3,4,5,6,7];
a.splice(4);
//刪除a[4]至結尾,同時返回刪除的值,即a=[1,2,3,4],返回[5,6,7]

var a = [1,2,3,4,5,6,7];
a.splice(3,3,"a","b");
//從a[3]開始,刪除3個元素(包括a[3]),同時在從a[3]開始插入"a","b"作為新的元素,返回刪除的值
//即a=[1,2,3,"a","b",7],返回[4,5,6]

var a = [1,2,3,4,5,6,7];
a.splice(3,0,["a",2],"k");
//返回[],a=[1,2,3,["a",2],"k",4,5,6,7] ,splice()不會對添加的數組拆包
* push()和pop()

var stack=[];

stack.push(1,2);//stack=[1,2],return 2(2表示數組長度)

stack.pop();//stack=[1],return 2

stack.push(3);//stack=[1,3],return 2(2表示數組長度)

stack.pop();//stack=[1],return 3

stack.push([4,5]);//stack=[1,[4,5]],return 2

stack.pop();//stack=[1],return [4,5]

stack.pop();//stack=[],return 1
* unshift()和shift() 和push()和pop()類似,不過是在數組的頭進行操作

var a=[2];
a.unshift(1);
//a=[1,2]
//IE(包括IE7)和標准的規定返回值卻不同,Gecko/Opera 中返回值為新數組的長度,而 IE 中沒有返回值,也就是返回值是 undefined。因此,編程時不要依賴這個返回值。

a.unshift(3,[4,5]);//a=[3,[4,5],1,2]

a.shift();
//返回3
* toString() toString等價於不加參數的join


4.5.8. Date對象

var now = new Date();
//默認是當前的時間和日期

var christmas = new Date(2000,11,25);
//月份從0開始計數,所以這是表示2000年12月25日

christmas.toLocaleString();//返回時間的本地表示,如果是中國大陸,這里返回"2000年12月25日 0:00:00 "
//如果不加toLocalString,christmas自動轉換為string時會用GMT時間
//GMT時間這里就是"Mon Dec 25 00:00:00 UTC+0800 2000 "

christmas.getDay()
//返回該日期是星期幾,比如這里返回1,注意星期天返回的是0

4.5.9. null 和 undefined
null : 無值,表示它的不是有效的Javascript類型 
undefined : 已經聲明但是沒有定義的變量的值,對象的一個不存在的屬性也是該值 
==運算符將兩者視為相等,

可以用===區別null和undefinedes


4.6. 函數

4.6.1. 定義函數
方式1:

function square(x){
        return x*x;
}
方式2:

var square = function(x){return x*x;}
方式3://比較笨拙

var square = new Funtion("x","return x*x");

4.6.2. 一個函數,多個函數名

var square = function(x){return x*x;}
var b=square;
var c=b(5);//c=25

4.6.3. 函數嵌套函數

function hypotenuse(){
        function square(x){
                return x*x;
        }
        return Math.sqrt(square(a)+square(b));
}

4.6.4. 函數參數
盡管函數定義時參數個數是固定的,但調用時可以傳遞任意多個參數,這些參數可以通過arguments[]訪問,即使是無名的.

arguments.length可以說明它所含的元素個數

注意:arguments不是數組(不可以用for...in循環),它是一個Aguments對象

arguments可以用於參數個數檢查,或接受任意數目參數...

function max()
{
var m=Number.NEGATIVE_INFINITY;
for(var i=0;i< arguments.length;i++)
        if(arguments[i]>m)m=arguments[i];
        
return m;
}

4.6.5. 函數自身的length
返回函數聲明中的參數的個數,通過arguments.callee.length訪問

//一個檢查參數是否相符的函數
function check(args){
        var actual=args.length;
        var expected=args.callee.length;
        if(actual!=expected){
                throw new Error("Wrong number of arguments");
        }
}

function f(x,y)
{
        check(arguments);
        return x+y;
}

4.6.6. arguments.callee : 遞歸無名函數
callee可以引用當前正在執行的函數

function(x)
{
if(x<1)return 1;
return x*arguments.callee(x-1);

4.6.7. 函數的靜態變量
類似在C++函數中聲明一個static變量

uniqueInteger.counter=0;//靜態變量
function uniqueInteger(){//每個返回一個不同的數 
        return uniqueInteger.counter++;
}

4.7. 作用域
沒有塊級作用域,其他類似於Java和C++.

即函數中無論在那里聲明的變量,在整個函數體中都是有定義的.如:

(見例1_4)

var i="global";

function test(o){

document.write(i);//i為undefined,即函數中i已被聲明,但沒定義
var i="local";

if(typeof o == "object")
        {
                var j=0;        //j在整個函數中都有定義,不限於這個循環
                for(var k=0;k<10;k++){//k在整個函數中都有定義,不限於這個循環
                        document.write(k);
                }
                document.write("out loop k=",k);//k仍然有定義,值為10
        }

document.write("out loop j=",j);//仍然有定義,如果o不是object(),則j沒有被初始化,值為undefined,否則為9

}

備注:把所有的變量集中在函數開頭聲明(不一定要定義)可以避免許多詭異的錯誤.

4.8. 引用
對與 數組 , 對象 , 函數 的拷貝只是拷貝了引用(相當於是個快捷方式),對任何一個副本的改動都會改動所有的副本

var a = [1 , 2 , 3];
var b = a;
a[0] = 99;
alert(b); //為99,2,3

a={x:1}
b=a;
a.x=2;
alert(b.x);//為2

4.9. ==(等於)和===(全等)

4.9.1. 等於
等於可以進行類型自動轉換,如

"2"==2
true==1
一個對象和字串或數字比較,會嘗試valueOf()和toString()轉換

null == undinfined

4.9.2. 全等 (否定為!==)
如果類型不同,則不相同 
NaN永遠不與任何值全等,包括它本身(可以用IsNaN()測試一個值是否是NaN) 
按字符原有編碼進行比較(等於操作在比較前先統一了編碼) 
null != undinfined 
對於數組,對象,函數等引用類型只有當他們是指向同一個實體時才相等,如

var a = [1,2,3];
var b = [1,2,3];
alert(a==b);//false

4.10. +加
加法是從左到右的 a=1+2+" blind mine" // a="3 blind mine" b="blind mine "+1+2 // a="blind mine 12"


4.11. 比較大小
符號> , < , >= , <=

任何和NaN的比較都返回false 
字串和數字比較,會把字串轉換為數字(如果轉換不成功,則其值為NaN),再比較 
如果對象可以被轉換為數字和字串,將執行數字轉換來比較

4.12. in
in運算符左邊是一個字串,右邊是一個對象,如果字串是對象的一個屬性名則返回true

var point = {x:1};
var has_x = "x" in point ; //true
var has_y = "y" in point; //false
var ts = "toString" in point; //true,繼承屬性

4.13. instanceof
instanceof運算符要求左邊是一個對象的實例,右邊是對象名,如果兩者相符返回true

var d=new Date();
d instanceof Date;//true
d instanceof Object;//true,所有的對象都是Object的實例
d instanceof Number;//false

4.14. typeof
返回對象的類型

typeof 1; //number
typeof "1";//string
typeof true;//boolean

typeof [1,2];//object
typeof {x:1};//object

typeof function(x){};//function

typeof xxx;//未定義的對象返回undefined

4.15. new
創建一個新的對象

o=new Date;

4.16. delete
刪除對象的屬性

var o={x:1,y:2};

delete o.x; //返回true
typeof o.x;//返回undefined

delete o.x;//刪除不存在的屬性,返回true

delete o;//不能刪除var聲明的對象,返回true

x=1;//不用var關鍵字,隱式聲明一個變量
delete x;//返回true
x;//一個運行時錯誤,IE6顯示為 " 'x'未定義 "
注意:delete只能刪除屬性值,不能刪除引用對象 如

var my = new Object;

my.hire = new Date;
my.fire = my.hire;

delete my.hire;

alert(my.fire);//顯示當前的時間

4.17. void
可以出現在任何操作數前,它作用是舍棄運算的結果,返回undefined.

常用於javascript : URL中.可以計算一個計算一個表達式的值,又不讓瀏覽器顯示它.如

<a href="javascript:void window.open();">Open</a><!-- 不加void,點擊后鏈接會消失,變為一個"[object]"字串 -->

4.18. []

//用於數組
var a=[21,3];
a[0];//21

//用於對象,比"."運算符的優勢是其要取的屬性名可以動態生成
var b={x1:1,x2:"zsp"};
b['x1'];//1
b['x'+2];//zsp

for(f in o){
        alert('o.'+f+'='+o[f]);//由於f是動態生成的,所有不能用" . "運算符
}
== if/else/while/do...while/for== 和C++類似

== for...in === 可循環對象的所有用戶定義屬性,包括繼承的(但是不包括內建屬性)


var o={x:1,y:2};
var a=[];
var i=0;

for(a[i++] in o);//把o的屬性名復制到一個數字中(注意,順序不固定)

for (i in a)
{
alert(a[i]);//循環一個數組
}

4.19. switch

function convert(x){
        switch(typeof x){
                case 'number':  //case后可以接任意表達式,不限於常量
                        return x.toString(16);//轉換為16進制
                case 'string':
                        return '"'+x+'"';
                case 'boolean':
                        return x.toSting().toUpperCase();
                default:
                        return x.toString();
        }
}

4.20. label(標簽)/break/continue
break,continue的基本用法和C++中類似,不過他們可以和label配合使用(有的像Java中的label,功能限制版的goto)

outerloop:
        for(var i=0;i!=10;i++)
        {
                for (var j=0;j<10;j++){
                        if(j>3)break;
                        if(i==2)break outerloop;//跳出外層循環
                        alert("j = "+j);
                }
                alert("i = "+i);
        }

4.21. throw / try...catch...finally
throw用來拋出異常,異常對象通常是一個Error對象或其子類型

function factorial(x){
if(x<0)throw new Error("x must not be negative");//x是負數就拋出異常
return x;
}
try...catch...finally捕捉異常

try{
//代碼
}
catch(e)
{
//僅當try塊拋出異常,才會執行,e為異常實例
//這個塊可以處理異常,也可以什么都不做
}
finally{
//無論是否有異常,這個塊中的語句都將被執行
}

4.22. 正值表達式
//todo


5. 瀏覽器中的Javascript概覽
window對象代表顯示瀏覽器的窗口,document對象代表文檔中窗口. 
定義函數的js文件一般放在head區 
<body>和<frameset>的onload在文檔被完全加載完成時觸發,onunload在文檔被卸載時觸發


5.1. window對象
window是全局對象,它的函數/屬性一般可以不加前綴直接調用。有時為了避免名字沖突,可以加window前綴


5.1.1. 簡單的對話框
注意:對話框中顯示的是純文本. * alert() 見圖js_0001.png

* confirm() 見圖js_0002.png


if(confirm("看我的非技術Blog嗎?/n/n我寫了不少詩哦 :)"))       location.replace("http://www.cnweblog.com/zuroc/");
* prompt() 見圖js_0003.png


n=prompt("你叫什么名字呢?","");//第二個參數是輸入的默認值

document.write("<h1>你好, "+n+"!<br/>我叫張沈鵬.</h1>");

5.1.2. 狀態欄
* status 瀏覽器狀態欄的顯示文本 * defaultStatus 瀏覽器狀態欄顯示文本的默認值 該屬性在firefox默認關閉,不介紹了


5.1.3. 定時器
* setTimeout() 安排一個JavaScript代碼在指定的時間后執行 * clearTimerout() 取消setTimeout的執行 * setInterval() 每隔指定的時間調用指定的函數 * clearInterval() 取消Interval的執行

function hi(){alert("hi!");}
setInterval("hi()",2000);//2000ms=2s

5.1.4. 錯誤處理onerror
只要給這個屬性賦了一個函數,那么這個窗口只要發生了javascript錯誤,該函數就會被調用.傳給錯誤處理函數的參數有三個,第一個是錯誤類型,第二個是引發錯誤的js腳本的Url,第三是發生錯誤的行號.

如果onerror返回true,它將屏蔽系統的錯誤處理程序

//如果你不想錯誤消息打攪用戶,無論你的代碼有多Bug
window.onerror = function(){return true;}
//不過,不建議你這樣做

5.1.5. 瀏覽器信息navigator
包含了瀏覽器的信息

* appName Web瀏覽器的名稱 * userAgent 瀏覽器在USER-AGENT HTTP標題中發送的字符串,通常包含了appName和appVersion * platform 平台,如Win32

//一個簡單瀏覽器探測器
var browser = {
    version: parseInt(navigator.appVersion),
    isNetscape: navigator.appName.indexOf("Netscape") != -1,
    isMicrosoft: navigator.appName.indexOf("Microsoft") != -1
};

5.1.6. 屏幕screen
* width,height 分辨率的寬和高 * availWidth , availHeight 去除了任務欄這樣的特性的寬和高 * colorDepth 屏幕的色深 見例子1_5.html


5.1.7. 打開窗口open

//注意,直接彈出窗口容易被瀏覽器廣告攔截了
window.open("http://www.cnweblog.com/zuroc/","窗口名","width=200,height=200,status=yes,resizable=yes");
//具體屬性希望那位大哥可以幫我列一下
//被打開的窗口可以用opener引用父窗口,如果是用戶自己打開的opener為null
//用open時一般要明確加上window前綴,因為Document也有open屬性
見例子1_5.html

window.close可以關閉你用javascript打開的窗口


5.1.8. 移動窗口/改變大小moveTo , moveBy , resizeTo , resizeBy
* moveTo 把窗口左上角移到指定的坐標 * moveTo 把窗口相對現在的位置移動指定的象素 * resizeTo 按照絕對大小調整窗口 * resizeBy 按照相對大小調整窗口 見例子1_5.html


5.1.9. 焦點控制 focus 和 blur
* focus() 將焦點給指定窗口,同時把窗口移動到最前端,使窗口可見,當open()打開窗口,如果第二個參數指定的窗口名已經存在,open不會自動使那個窗口可見,這時就要調用該函數 * blur() 放棄焦點,這時窗口將被至於窗口隊列的最后(這就什么sohu背投廣告的原理吧) 見例子1_5.html


5.1.10. 文檔滾動
* scrollBy() 相對當前位置滾動指定的象素 * scrollTo() 將文檔滾動到一個絕對位置,文檔的左上角的坐標為(0,0)


5.1.11. 當前地址欄 location
它本身代表當前窗口的URL,它還有各個屬性如下 * location.protocol 用的協議,如在本地直接打開網頁則是file: * location.host 用的域名 * location.pathname 域名后的網址路徑.如"/F:/Javascript絕對簡明教程/example/test.html " * location.search 查詢的內容 * location.reload() 刷新當前線 * location.replace() 跳轉到指定的URL,與直接給location賦值不同的是,這樣不會在瀏覽歷史中留下記錄(也就是后退不會到該頁)

//一個把URL串中查詢內容解析為鍵值對的函數
function getArgs(){
        var args=new Object;
        var query=location.search.substring(1);//或取查詢串
        var pairs=query.split(",");     //在逗號處分開
        for(var i=0;i<pairs.length;i++){
                var pos=pair[i].indexOf("=");
                var argname=pairs[i].substring(0,pos);
                var value=pairs[i].substring(pos+1);
                args[argname]=decodeURIComponent(value);
        }
        return args;
}
//調用可以這樣
var args=getArgs();
if(args.x)x=parseInt(args.x);

//檢查瀏覽器是否支持DOM,如果不支持則跳轉
if (!document.getElementById) location = "staticpage.html";

5.1.12. 歷史History
腳本不能真正訪問History數組,但是可以調用它的函數 * back() 后退 * forward() 前進 * go() 后退/前進指定的頁數


5.1.13. 框架
一個窗口可以用frames,parent,top引用其他屬性

每個窗口有一個frame[]數組(如果一個窗口沒有框架則它的frame[]是空的,frames.length==0),frame[0]表示它的第一個子框架,如此類推

每個窗口還有一個parent屬性,為包含這個窗口的window對象,這樣一個窗口通過諸如parent.frames[1]的方式,引用他的兄弟窗口

對於頂層窗口,有parent==window

對於框架中的框架,可以用top直接引用最頂層的窗口

見圖js_0004.png

框架可以用name指定名字,這個名字可以為鏈接的target值.當這個鏈接被激活的時候會在指定的框架中顯示內容

在javascript也可以通過名字訪問框架,如一個框架如下

<frame name="table_of_contents" src="top.html">
 則可以通過parent.table_of_contents方法訪問該框架

需要注意的在一個框架定義的函數/變量,在另一個框架中要通過框架名來調用

見例1_6.html


5.2. 文檔Documents

5.2.1. 基本常識

5.2.1.1. 屬性
* bgColor , fgColor 文檔背景色,前景色(不贊成使用的屬性) * lastModified 文檔的最后修改時間

//可以在文檔末加入
  最后更新:<script>document.write(document.lastModified);</script>
* referrer 如果該屬性存在,則返回一個鏈接,表示用戶是由哪個網頁鏈接到該頁的

<script>
//如果你想其他由網站鏈接到該頁的用戶先訪問你的首頁
if (document.referrer == "" || document.referrer.indexOf("mysite.com") == -1)
    window.location = "http://home.mysite.com";
</script>

5.2.1.2. 數組
* title 文檔標題 * URL 等同於window的location.href * anchors[] 所有有name屬性的a標記 * forms[] 所有form標記,每個form還有一個element[]數組 * images[] 所有的<img>標簽,可以改變它的src屬性來改變圖象 * link[] 文檔中所有的超鏈接,和window的location一樣有protocol, hostname,pathname等屬性


<form name="f1"><input type="button" value="Push Me" name="zipcode"></form>

//如果一個元素有name還可以這樣訪問
document.forms.f1    
document.forms["f1"] 

//對於它的子元素可以這樣訪問
document.shipping.zipcode

//如果有重名的元素,以上的引用方法將返回一個數組

5.2.2. DOM樹
見圖js_0005.png 對於樹上的節點可以用firstChild, lastChild, nextSibling, previousSibling, 和 parentNode屬性來歷遍

appendChild(), removeChild(), replaceChild(), 和 insertBefore() 可以在文檔中動態的添加/刪除節點

每個節點都有一個nodeType屬性,表明了它的類型

Interface                       nodeType constant                       nodeType value

Element                 Node.ELEMENT_NODE                        1
Text                            Node.TEXT_NODE                           3 
Document                        Node.DOCUMENT_NODE                       9
Comment                 Node.COMMENT_NODE                        8
DocumentFragment  Node.DOCUMENT_FRAGMENT_NODE 11
Attr                            Node.ATTRIBUTE_NODE                      2

getAttribute(), setAttribute(), removeAttribute() 可以用來操作屬性,標准的Html元素的屬性也可以通過這種方式訪問 getAttributeNode()可以返回一個Attr對象,它有一個specified屬性,可以判斷文檔是否指定了該屬性,或判斷它是否是默認值


//歷便一個DOM樹
function countTags(n) {                         // n is a Node
    var numtags = 0;                            // Initialize the tag counter
    if (n.nodeType == 1 /*Node.ELEMENT_NODE*/)  // Check if n is an Element
        numtags++;                              // Increment the counter if so
    var children = n.childNodes;                // Now get all children of n
    for(var i=0; i < children.length; i++) {    // Loop through the children
        numtags += countTags(children[i]);      // Recurse on each one
    }
    return numtags;                             // Return the total
}
alert('This document has ' + countTags(document) + ' tags');

5.2.2.1. 搜索文檔的特定元素
* document.getElementsByTagName() 返回指定標簽名的數組

//雖然只有一個body,還是返回一個數組
document.getElementsByTagName("body")[0];

//有多少表格
var tables = document.getElementsByTagName("table");
alert("This document contains " + tables.length + " tables");

* document.getElementById() 返回id號為指定值元素,因為每個id應該的獨一無二的,所以該方法最多返回一個元素

<p id="specialParagraph">
var myParagraph = document.getElementById("specialParagraph");
* document.getElementsByName() 返回name屬性為指定值的元素的數組

// Find <a name="top">
var link = document.getElementsByName("top")[0];
// Find all <input type="radio" name="shippingMethod"> elements
var choices = document.getElementsByName("shippingMethod");

5.2.2.2. 動態改變文檔內容
* Document.createElement() * Document.createTextNode() * Node.appendChild() * Node.insertBefore() * Node.replaceChild()


5.2.2.3. 一個動態改變Document內容的演示

<!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>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>test</title>
<script>
function sortkids(e) {
     // This is the element whose children we are going to sort
     if (typeof e == "string") e = document.getElementById(e);

     // Transfer the element (but not text node) children of e to a real array
     var kids = [];
     for(var x = e.firstChild; x != null; x = x.nextSibling)
         if (x.nodeType == 1 /* Node.ELEMENT_NODE */) kids.push(x);

     // Now sort the array based on the text content of each kid.
     // Assume that each kid has only a single child and it is a Text node
     kids.sort(function(n, m) { // This is the comparator function for sorting
                   var s = n.firstChild.data; // text of node n
                   var t = m.firstChild.data; // text of node m
                   if (s < t) return -1;      // n comes before m
                   else if (s > t) return 1;  // n comes after m
                   else return 0;             // n and m are equal
               });

     // Now append the kids back into the parent in their sorted order.
     // When we insert a node that is already part of the document, it is
     // automatically removed from its current position, so reinserting
     // these nodes automatically moves them from their old position
     // Note that any text nodes we skipped get left behind, however.
     for(var i = 0; i < kids.length; i++) e.appendChild(kids[i]);
}
</script>
</head>

<body>


<ul id="list"> <!-- This is the list we'll sort -->
<li>one<li>two<li>three<li>four <!-- items are not in alphabetical order -->
</ul>
<!-- this is the button that sorts the list -->
<button onclick="sortkids('list')">Sort list</button>
</body>
</html>

5.2.2.4. 一個把文章中字母都變為大寫的演示

// This function recursively looks at Node n and its descendants,
// converting all Text node data to uppercase
function upcase(n) {
    if (n.nodeType == 3 /*Node.TEXT_NODE*/) {
        // If the node is a Text node, change its text to uppercase.
        n.data = n.data.toUpperCase();
        //你也可以用appendData(), insertData(), deleteData(), replaceData()來更改數據
    }
    else {
        // If the node is not a Text node, loop through its children
        // and recursively call this function on each child.
        var kids = n.childNodes;
        for(var i = 0; i < kids.length; i++) upcase(kids[i]);
    }
}


5.2.2.5. 把指定標簽改為粗體

<script>
// This function takes a Node n, replaces it in the tree with an Element node
// that represents an HTML <b> tag, and then makes the original node the
// child of the new <b> element.
function embolden(n) {
    if (typeof n == "string") n = document.getElementById(n); // Lookup node
    var b = document.createElement("b"); // Create a new <b> element
    var parent = n.parentNode;           // Get the parent of the node
    parent.replaceChild(b, n);           // Replace the node with the <b> tag
    b.appendChild(n);                    // Make the node a child of the <b> element
}
</script>

<!-- A couple of sample paragraphs -->
<p id="p1">This <i>is</i> paragraph #1.</p>
<p id="p2">This <i>is</i> paragraph #2.</p>
<!-- A button that invokes the embolden() function on the element named p1 -->
<button onclick="embolden('p1');">Embolden</button>

 

5.2.2.6. 更改屬性

var headline = document.getElementById("headline");  // Find named element
headline.setAttribute("align", "center");            // Set align='center'

5.2.2.7. 臨時容器DocumentFragment
DocumentFragment是一個用來裝載DOM對象的臨時容器,將他寫入文檔其實是將它的子元素寫入節點

// 翻轉元素
function reverse(n) {
    // Create an empty DocumentFragment as a temporary container
    var f = document.createDocumentFragment();
    // Now loop backward through the children, moving each one to the fragment.
    // The last child of n becomes the first child of f, and vice-versa.
    // Note that appending a child to f automatically removes it from n.
    while(n.lastChild) f.appendChild(n.lastChild);

    // Finally, move the children of f all at once back to n, all at once.
    n.appendChild(f);
}
==== 直接插入Html代碼innerHTML ==== 雖然不是W3C的標准,但是事實上的標准,類似的還有outerHTML, innerText, 和outerText 
var table = document.createElement("table");  // Create the <table> element
table.border = 1;                             // Set an attribute
// Add a Name|Type|Value header to the table

5.2.2.8. 選中內容 getSelection
還不是標准,但還是可用的,參考 http://www.quirksmode.org/js/selected.html

Hi , everybody . My name is Zsp .
function getSelectedText() {
    if (window.getSelection) {
        // This technique is the most likely to be standardized.
        // getSelection() returns a Selection object, which we do not document.
        return window.getSelection().toString();
    }
    else if (document.selection) {
        // This is the IE-specific technique.
        // We do not document the IE selection property or TextRange objects.
        return document.selection.createRange().text;
    }
    //現在可以省略了
    else if (document.getSelection) {
        // This is an older, simpler technique that returns a string
        return document.getSelection();
    }
}

//一個實際使用的演示
<a href="javascript:
    var q;
    if (window.getSelection) q = window.getSelection().toString();
    else if (document.getSelection) q = document.getSelection();
    else if (document.selection) q = document.selection.createRange().text;
    void window.open('http://en.wikipedia.org/wiki/' + q);
">
Look Up Selected Text In Wikipedia
</a>

5.2.3. CSS

//一個用來隱藏廣告代碼的演示
var imgs = document.getElementsByTagName("img");  // Find all images
for(var i = 0; i < imgs.length; i++) {            // Loop through them
    var img=imgs[i];
    if (img.width == 468 && img.height == 60)     // If it's a 468x60 banner...
        img.style.visibility = "hidden";          // hide it!
}
* javascript與css的名字映射,如font-family映射為fontFamily,諸如此類.另外css中的float映射為cssFloat,如此類推

e.style.position = "absolute";
e.style.fontFamily = "sans-serif";
e.style.backgroundColor = "#ffffff";
e.style.left = "300px";
e.style.margin = topMargin + "px " + rightMargin + "px " +
                 bottomMargin + "px " + leftMargin + "px";

5.2.3.1. 當前的CSS設置
W3C規定了getComputedStyle()函數來獲取CSS元素的經過各種效果復合過后的當前值

但是IE不支持標准,但它有每個元素都有一個currentStyle屬性,可以取得同樣的效果

//一段兼容的代碼
<p>
Look Up Selected Text In Wikipedia
</p>

<script>
var p = document.getElementsByTagName("p")[0]; // Get first paragraph of doc
var typeface = "";                             // We want its typeface
if (p.currentStyle)                            // Try simple IE API first
    typeface = p.currentStyle.fontFamily;
else if (window.getComputedStyle)              // Otherwise use W3C API
    typeface = window.getComputedStyle(p, null).fontFamily;
alert(typeface);
</script>

5.2.3.2. 指定樣式表

<head>
<!-- Here we define four stylesheets, using <link> and <style> tags. -->
<!-- Two of the <link>ed sheets are alternate and so disabled by default. -->
<!-- All have id attributes so we can refer to them by name. -->
<link rel="stylesheet" type="text/css" href="ss0.css" id="ss0">
<link rel="alternate stylesheet" type="text/css" href="ss1.css"
      id="ss1" title="Large Type">
<link rel="alternate stylesheet" type="text/css" href="ss2.css"
      id="ss2" title="High Contrast">
<style id="ss3" title="Sans Serif">
body { font-family: sans-serif; }
</style>

<script>
// This function enables or disables a stylesheet specified by id.
// It works for <link> and <style> elements.
function enableSS(sheetid, enabled) {
    document.getElementById(sheetid).disabled = !enabled;
}
</script>
</head>
<body>

<!-- This is a simple HTML form for enabling and disabling stylesheets -->
<!-- It is hardcoded to match the sheets in this document but could be -->
<!-- dynamically generated using stylesheet titles instead. -->
<form>
<input type="checkbox" onclick="enableSS('ss0', this.checked)" checked>Basics
<br><input type="checkbox" onclick="enableSS('ss1', this.checked)">Large Type
<br><input type="checkbox" onclick="enableSS('ss2', this.checked)">Contrast
<br><input type="checkbox" onclick="enableSS('ss3', this.checked)" checked>
Sans Serif
</form>

 

5.2.4. 事件驅動

5.2.4.1. HTML中事件設置
html元素對事件進行響應(不要放在<script>塊中)

<input type="checkbox" name="opts" value="ignore-case" onclick="ignore-case=this.checked;">

其中onclick就是事件觸發器,常用的還有onmousedown,onmouseup,onmouseover,onmouseout,onchange,onsubmit,onreset


5.2.4.2. Javascript中事件設置

<form name="myform" onsubmit="return validateform();">...</form>
//以上事件設置在javascript中的等效代碼如下,注意,javascript中的所有事件名都是小寫的
document.myform.onsubmit = validateform;

//可以在腳本中批量設置事件觸發器
function confirmAllLinks( ) {
    for(var i = 0; i < document.links.length; i++) {
        document.links[i].onclick = confirmLink;
    }
}


5.2.4.3. 事件列表

事件名                     支持該事件的元素
onabort                 <img>
Image loading interrupted.

onblur                   <button>, <input>, <label>, <select>, <textarea>, <body>
 Element loses input focus.    

onchange                        <input>, <select>, <textarea>
Selection in a <select> element or other form element loses focus, and its value has changed since it gained focus.

 onclick                        Most elements
 Mouse press and release; follows mouseup event. Return false to cancel default action (i.e., follow link, reset, submit).
 
 ondblclick                     Most elements
 Double-click.

 onerror                        <img>   
 Error when loading image.
  
onfocus                 <button>, <input>, <label>, <select>, <textarea>, <body>
 Element gains input focus.

 onkeydown               Form elements and <body>
 Key pressed down. Return false to cancel.

 onkeypress             Form elements and <body>
 Key pressed; follows keydown. Return false to cancel.
 
onkeyup                 Form elements and <body>
Key released; follows keypress.
 
onload                  <body>, <frameset>, <img>
Document load complete.
 
 
onmousedown             Most elements
Mouse button pressed.
 
 
onmousemove             Most elements
Mouse moved.

 
onmouseout              Most elements
Mouse moves off element.
 
onmouseover             Most elements
Mouse moves over element.

onmouseup               Most elements
Mouse button released.
 
 
onreset                 <form>
Form reset requested. Return false to prevent reset.
 
 onresize                       <body>, <frameset>
 Window size changes.

 onselect                       <input>, <textarea>     
 Text selected.
 
onsubmit                        <form>
Form submission requested. Return false to prevent submission.
 
onunload                        <body>, <frameset>
離開頁面時

5.2.4.4. 原始事件vs語義事件
* 原始事件:如鍵盤輸入,鼠標按下 * 語義事件:如Sumbit事件,他可以由提交按鈕上的onmousedown, onmouseup和onclick產生的.也可以由鍵盤上的回車產生.總的來說,語義事件往往與產生事件的設備無關.


5.2.4.5. 同時執行原有動作和自定義動作

var b=document.myform.mybutton;//我們需要的按鈕

var olderHandler=b.onclick;//HTML原有自定義事件

function newHandler(){
//自定義動作
}

b.onclick=function(){olderHandler();newHandler();}

5.2.4.6. 事件的返回值
事件默認返回true,會繼續執行默認動作.

onsubmit , onclick , onkeydown , onkeypress , onmousedown , onmouseup 和 onreset 返回false會阻止他們的默認行為發生.


5.2.4.7. this關鍵字

button.onclick=o.mymethod;//這時o.mymethod中的this指代的是button

button.onclick=function(){o.mymethod();}//這時o.mymethod中的this指代是o

5.2.4.8. 2級DOM標准的消息機制
這種事件處理方式被Firefox系列等支持.

瀏覽器中,當事件被觸發時的流程

1.capturing(捕捉):事件按照Document樹從上往下傳播直到目標節點,如果目標的 任何一個父元素注冊了caputure該事件的函數, 則會運行這些函數

2.運行目標節點的該事件處理函數

3.bubbling(起泡):事件將從目標元素回傳至Document根節點(語義事件一般不起泡).

4.如果存在默認事件,執行它

2級DOM中事件名稱是原始事件名把on前綴去除.如"onmousedown"在2級DOM中叫"mousedown"

* 在事件傳播過程中,任何事件處理函數都可以調用stopPropagation()來停止事件的傳播.

* addEventListener來注冊事件,removeEventListener()來移除事件,你也可以給Text節點注冊事件處理函數

var mydiv=document.getElementById("mydiv");

//捕捉<div>中所有的mousedown事件
//一個元素的同一個事件可以注冊多個處理函數,但是他們的調用順序不一定是注冊順序
mydiv=addEventListener(
"mousedown",
function(event){
                //函數體
        },
false//為true則在傳播階段捕捉,為false在起泡階段捕捉
);


//Firefox中一個對象實現了EventListener接口和handleEvent()方法,便可以直接作為一個參數傳給addEventHandler
//一個簡單的函數,可以實現類似效果
function registerObjectEventHandler(element, eventtype, listener, captures) {
    element.addEventListener(
                             eventtype,
                             function(
                                  event//一個事件對象
                             ) 
                             { listener.handleEvent(event); }
                             captures
                             );
}
一個事件被觸發時會產生一個相應的事件對象,這個對象提供了關於這個事件的詳細信息,如:發生坐標 如在e.addEventListener("click", f, false);中,事件對象會作為參數傳給f

事件對象的類型分 * 模塊名:HTMLEvents

事件接口:Event

觸發事件:abort, blur, change, error, focus, load, reset, resize, scroll, select, submit, unload

* 模塊名:MouseEvents

事件接口:MouseEvent

觸發事件:click, mousedown, mousemove, mouseout, mouseover, mouseup

* 模塊名:UIEvents

事件接口:UIEvent 觸發事件:DOMActivate, DOMFocusIn, DOMFocusOut 
                        事件<->類型表
C:表示能否用preventDefault()取消默認動作.          
事件                      類型                      起泡              C               由...支持
abort           Event            yes            no               <img>, <object>

blur                    Event             no            no               <a>, <area>, <button>, <input>, <label>, <select>, <textarea>

change          Event            yes            no               <input>, <select>, <textarea>

click                   MouseEvent       yes            yes              screenX, screenY, clientX, clientY,altKey,
                                                                                 ctrlKey, shiftKey, metaKey, button, detail

error                   Event            yes            no               <body>, <frameset>, <img>, <object>

focus           Event             no            no               <a>, <area>, <button>, <input>, <label>, <select>, <textarea>

load                    Event             no            no               <body>, <frameset>, <iframe>, <img>, <object>

mousedown       MouseEvent       yes            yes              screenX, screenY, clientX, clientY, altKey, 
                                                                                 ctrlKey, shiftKey, metaKey, button, detail

mousemove       MouseEvent       yes             no              screenX, screenY, clientX, clientY, altKey,
                                                                                 ctrlKey, shiftKey, metaKey
 
mouseout                MouseEvent       yes             yes            screenX, screenY, clientX, clientY, altKey,
                                                                                ctrlKey, shiftKey, metaKey, relatedTarget
 
mouseover       MouseEvent       yes             yes             screenX, screenY, clientX, clientY, altKey,
                                                                                 ctrlKey, shiftKey, metaKey, relatedTarget
 
mouseup         MouseEvent       yes             yes             screenX, screenY, clientX, clientY, altKey,
                                                                                 ctrlKey, shiftKey, metaKey, button, detail
 
reset                   Event            yes             no              <form>
 
resize          Event            yes             no              <body>, <frameset>, <iframe>
 
scroll                  Event            yes             no              <body>
 
select          Event            yes             no              <input>, <textarea>
 
submit          Event            yes             yes             <form>
 
unload          Event            no              no              <body>, <frameset>
 
DOMActivate     UIEvent          yes            yes               detail
 
DOMFocusIn      UIEvent          yes            no                none
 
DOMFocusOut   UIEvent            yes            no                none

5.2.4.8.1. Event事件對象
Event是其他所有的事件父類,所有的事件都實現了這個接口.

支持屬性:

type 觸發的事件的名稱,如"click" 或 "mouseover"

target 發生事件的節點

currentTarget 當前正在處理該事件的節點,在捕捉階段或起泡階段他的值與target的值不同.在事件處理函數中應該用這個屬性而不是this來指代當前處理的節點

eventPhase 一個數字,指定了當前事件所處的傳播過程的階段.它的值是常量,可以是Event.CAPTURING_PHASE或Event.AT_TARGET或Event.BUBBLING_PHASE.

timeStamp 一個Date對象,表明事件的發生時間

bubbles 布爾值,表明該事件是否起泡

cancelable 布爾值,表明事件是否可以用preventDefault()方法來取消默認的動作.

stopPropagation( ) 停止事件的傳播

preventDefault( ) 阻止默認事件發生,和0級DOM中返回false的作用類似


5.2.4.8.2. UIEvent事件對象
UIEvent是Event的一個子類

支持屬性:

view 視圖,發生事件的window對象

detail 一個數字,提供關於該事件的額外信息.對於click事件,mousedown事件和mouseup事件表示連續點擊的次數,如1表示單擊,2表示雙擊,3表示連續點3次(注意:每次點擊還是生成一個事件,in a word,detail為2的鼠標事件前總有一個detail為1的鼠標事件,detail為3的鼠標事件前總有一個detail為2的鼠標事件).

對於DOMActivate事件,1表示正常激活,2表示超級激活(如雙擊鼠標或同時按下Shift和Enter鍵)


5.2.4.9. MouseEvent事件對象
MouseEvent是UIEvent的一個子類

支持屬性:

button 一個數字,表明在mousedown,mouseup和click中,那個鼠標鍵改變了狀態.0表示左鍵,1表示中鍵,2表示右鍵.

altKey , ctrlKey, metaKey, shiftKey 表明對應的鍵盤上的鍵的狀態(PC上,Meta鍵通常對應 Alt 鍵)

screenX , screenY 鼠標指針相對於屏幕左上角X,Y坐標,如果你想在鼠標附近彈出一個窗口,這個值很有用

clientX, clientY 鼠標指針相對於瀏覽器頁面顯示部分左上角的X,Y坐標,注意,這個值不考慮文檔滾動.如果需要相對於文檔的位置,IE中可以加上document.body.scrollLeft和document.body.scrollTop,其他瀏覽器可以加上window.pageXOffset and window.pageYOffset

relatedTarget 該屬性僅對mouseover和mouseout生效.

對於mouseover是它離開的節點,對於mouseout是它進入的節點.


5.2.4.9.1. MutationEvent
不常用,不介紹


5.2.4.10. IE事件模型
IE不完全支持標准事件模型,它使用IE的Event模型,它有以下重要屬性.

type 兼容DOM

srcElement 等價DOM中的target

button 和DOM的MouseEvent的同名屬性類似,但1為左鍵,2為右鍵,4為中鍵,如果多個鍵同時按下,會把他們的屬性值相加.如同時按下左右鍵,值為3

clientX , clientY 兼容DOM

offsetX, offsetY 鼠標指針相對於源元素的位置,用他們可以確定點擊了Image的哪個象素,2級DOM無等價事件

altKey , ctrlKey, shiftKey 等價於DOM,無metaKey屬性

keyCode 聲明了keydown,keyup的鍵代碼,和keypress事件的Unicode字符.用String.fromCharCode()方法可以把字符代碼轉換為字符.()

fromElement, toElement 類似DOM的relatedTarget

cancelBubble 設置為True時,阻止事件的起泡.類似DOM的stopPropagation( )

returnValue 設置為false時,阻止默認行為.類似DOM的preventDefault( )


/*
 * Handler.js -- Portable event-handler registration functions
 *
 * This module defines event-handler registration and deregistration functions
 * Handler.add( ) and Handler.remove( ). Both functions take three arguments:
 *
 *   element: the DOM element, document, or window on which the handler
 *      is to be added or removed.
 *
 *   eventType: a string that specifies the type of event for which the
 *      handler is to be invoked. Use DOM-standard type names, which do
 *      not include an "on" prefix. Examples: "click", "load", "mouseover".
 *
 *   handler: The function to be invoked when an event of the specified type
 *      occurs on the specified element. This function will be invoked as
 *      a method of the element on which it is registered, and the "this"
 *      keyword will refer to that element. The handler function will be
 *      passed an event object as its sole argument. This event object will
 *      either be a DOM-standard Event object or a simulated one. If a
 *      simulated event object is passed, it will have the following DOM-
 *      compliant properties: type, target, currentTarget, relatedTarget,
 *      eventPhase, clientX, clientY, screenX, screenY, altKey, ctrlKey,
 *      shiftKey, charCode, stopPropagation( ), and preventDefault( )
 *
 * Handler.add( ) and Handler.remove( ) have no return value.
 *
 * Handler.add( ) ignores duplicate registrations of the same handler for
 * the same event type and element. Handler.remove( ) does nothing if called
 * to remove a handler that has not been registered.
 *
 * Implementation notes:
 *
 * In browsers that support the DOM standard addEventListener( ) and
 * removeEventListener( ) event-registration functions, Handler.add( ) and
 * Handler.remove( ) simply invoke these functions, passing false as the
 * third argument (meaning that the event handlers are never registered as
 * capturing event handlers).
 *
 * In versions of Internet Explorer that support attachEvent( ), Handler.add( )
 * and Handler.remove() use attachEvent( ) and detachEvent( ). To
 * invoke the handler function with the correct this keyword, a closure is
 * used. Since closures of this sort cause memory leaks in Internet Explorer,
 * Handler.add( ) automatically registers an onunload handler to deregister
 * all event handlers when the page is unloaded. To keep track of
 * registered handlers, Handler.add( ) creates a property named _allHandlers on
 * the window object and creates a property named _handlers on any element on
 * which a handler is registered.
 */
var Handler = {};

// In DOM-compliant browsers, our functions are trivial wrappers around
// addEventListener( ) and removeEventListener( ).
if (document.addEventListener) {
    Handler.add = function(element, eventType, handler) {
        element.addEventListener(eventType, handler, false);
    };

    Handler.remove = function(element, eventType, handler) {
        element.removeEventListener(eventType, handler, false);
    };
}
// In IE 5 and later, we use attachEvent( ) and detachEvent( ), with a number of
// hacks to make them compatible with addEventListener and removeEventListener.
else if (document.attachEvent) {
    Handler.add = function(element, eventType, handler) {
        // Don't allow duplicate handler registrations
        // _find( ) is a private utility function defined below.
        if (Handler._find(element, eventType, handler) != -1) return;

        // To invoke the handler function as a method of the
        // element, we've got to define this nested function and register
        // it instead of the handler function itself.
        var wrappedHandler = function(e) {
            if (!e) e = window.event;

            // Create a synthetic event object with partial compatibility
            // with DOM events.
            var event = {
                _event: e,    // In case we really want the IE event object
                type: e.type,           // Event type
                target: e.srcElement,   // Where the event happened
                currentTarget: element, // Where we're handling it
                relatedTarget: e.fromElement?e.fromElement:e.toElement,
                eventPhase: (e.srcElement==element)?2:3,

                // Mouse coordinates
                clientX: e.clientX, clientY: e.clientY,
                screenX: e.screenX, screenY: e.screenY,
               // Key state
                altKey: e.altKey, ctrlKey: e.ctrlKey,
                shiftKey: e.shiftKey, charCode: e.keyCode,

                // Event-management functions
                stopPropagation: function( ) {this._event.cancelBubble = true;},
                preventDefault: function( ) {this._event.returnValue = false;}
            }

            // Invoke the handler function as a method of the element, passing
            // the synthetic event object as its single argument.
            // Use Function.call( ) if defined; otherwise do a hack
            if (Function.prototype.call)
                handler.call(element, event);
            else {
                // If we don't have Function.call, fake it like this.
                element._currentHandler = handler;
                element._currentHandler(event);
                element._currentHandler = null;
            }
        };

        // Now register that nested function as our event handler.
        element.attachEvent("on" + eventType, wrappedHandler);

        // Now we must do some record keeping to associate the user-supplied
        // handler function and the nested function that invokes it.
        // We have to do this so that we can deregister the handler with the
        // remove( ) method and also deregister it automatically on page unload.

        // Store all info about this handler into an object.
        var h = {
            element: element,
            eventType: eventType,
            handler: handler,
            wrappedHandler: wrappedHandler
        };

        // Figure out what document this handler is part of.
        // If the element has no "document" property, it is not
        // a window or a document element, so it must be the document
        // object itself.
        var d = element.document || element;
        // Now get the window associated with that document.
        var w = d.parentWindow;

        // We have to associate this handler with the window,
        // so we can remove it when the window is unloaded.
        var id = Handler._uid( );  // Generate a unique property name
        if (!w._allHandlers) w._allHandlers = {};  // Create object if needed
        w._allHandlers[id] = h; // Store the handler info in this object

        // And associate the id of the handler info with this element as well.
        if (!element._handlers) element._handlers = [];
        element._handlers.push(id);

        // If there is not an onunload handler associated with the window,
        // register one now.
        if (!w._onunloadHandlerRegistered) {
            w._onunloadHandlerRegistered = true;
            w.attachEvent("onunload", Handler._removeAllHandlers);
        }
    };

    Handler.remove = function(element, eventType, handler) {
        // Find this handler in the element._handlers[] array.
        var i = Handler._find(element, eventType, handler);
        if (i == -1) return;  // If the handler was not registered, do nothing

        // Get the window of this element.
        var d = element.document || element;
        var w = d.parentWindow;

        // Look up the unique id of this handler.
        var handlerId = element._handlers[i];
        // And use that to look up the handler info.
        var h = w._allHandlers[handlerId];
        // Using that info, we can detach the handler from the element.
        element.detachEvent("on" + eventType, h.wrappedHandler);
        // Remove one element from the element._handlers array.
        element._handlers.splice(i, 1);
        // And delete the handler info from the per-window _allHandlers object.
        delete w._allHandlers[handlerId];
    };

    // A utility function to find a handler in the element._handlers array
    // Returns an array index or -1 if no matching handler is found
    Handler._find = function(element, eventType, handler) {
        var handlers = element._handlers;
        if (!handlers) return -1;  // if no handlers registered, nothing found

        // Get the window of this element
        var d = element.document || element;
        var w = d.parentWindow;

        // Loop through the handlers associated with this element, looking
        // for one with the right type and function.
        // We loop backward because the most recently registered handler
        // is most likely to be the first removed one.
        for(var i = handlers.length-1; i >= 0; i--) {
            var handlerId = handlers[i];        // get handler id
            var h = w._allHandlers[handlerId];  // get handler info
            // If handler info matches type and handler function, we found it.
            if (h.eventType == eventType && h.handler == handler)
                return i;
        }
        return -1;  // No match found
    };

    Handler._removeAllHandlers = function( ) {
        // This function is registered as the onunload handler with
        // attachEvent. This means that the this keyword refers to the
        // window in which the event occurred.
        var w = this;

        // Iterate through all registered handlers
        for(id in w._allHandlers) {
            // Get handler info for this handler id
            var h = w._allHandlers[id];
            // Use the info to detach the handler
            h.element.detachEvent("on" + h.eventType, h.wrappedHandler);
            // Delete the handler info from the window
            delete w._allHandlers[id];
        }
    }

    // Private utility to generate unique handler ids
    Handler._counter = 0;
    Handler._uid = function( ) { return "h" + Handler._counter++; };
}

 

5.2.4.11. Key Event事件對象
由於DOM中沒有相應的標准,這里的用法是相當混亂的,我將分別介紹一下IE和Firefox系列的模型.

通常,一次按鍵有3個過程keydown, keypress, 和 keyup.

keypress為輸入的ASCII字符,如"@"等.不可打印字符如空格,回車, 退格,方向鍵,F1到F12,如果沒有對應的ASCII碼,不產生該事件

keypress,keyup為"virtual keycode" ,如同時按下 "shift"和"2", 發生事件"shift-2"

altKey, ctrlKey, shiftKey屬性可以用來查詢這三個鍵的狀態(ALT在IE中不產生keypress事件)

為了獲得嵌入的字符,Firefox定義了兩個屬性keyCode(返回"virtual keycode")和charCode(返回字符編碼),對於不可打印字符,charCode是0.

IE中只有keyCode屬性,為keydown事件時, keyCode是virtual keycode;為keypress事件時, keyCodes是字符編碼

String.fromCharCode( )可以把字符編碼轉換為字符.


<input type="text" class="spellInput" onKeyPress="if(event.keyCode==13 && this.value!=''){this.value='you have enter something'}" />

A Keymap class for keyboard shortcuts
/*
 * Keymap.js: bind key events to handler functions.
 *
 * This module defines a Keymap class. An instance of this class represents a
 * mapping of key identifiers (defined below) to handler functions. A
 * Keymap can be installed on an HTML element to handle keydown and keypress
 * events. When such an event occurs, the Keymap uses its mapping to invoke
 * the appropriate handler function.
 *
 * When you create a Keymap, pass a JavaScript object that represents the
 * initial set of bindings for the Keymap. The property names of this object
 * are key identifers, and the property values are the handler functions.
 *
 * After a Keymap has been created, you can add new bindings by passing a key
 * identifer and handler function to the bind( ) method.

You can remove a
 * binding by passing a key identifier to the unbind( ) method.

 *
 * To make use of a Keymap, call its install( ) method, passing an HTML element,
 * such as the document object. install( ) adds an onkeypress and onkeydown
 * event handler to the specified object, replacing any handlers previously set
 * on those properties. When these handlers are invoked, they determine the
 * key identifier from the key event and invoke the handler function, if any,
 * bound to that key identifier. If there is no mapping for the event, it uses
 * the default handler function (see below), if one is defined. A single
 * Keymap may be installed on more than one HTML element.
 *
 * Key Identifiers
 *
 * A key identifier is a case-insensitive string representation of a key plus
 * any modifier keys that are held down at the same time. The key name is the
 * name of the key: this is often the text that appears on the physical key of
 * an English keyboard. Legal key names include "A", "7", "F2", "PageUp",
 * "Left", "Delete", "/", "~". For printable keys, the key name is simply the
 * character that the key generates. For nonprinting keys, the names are
 * derived from the KeyEvent.DOM_VK_ constants defined by Firefox. They are
 * simply the constant name, with the "DOM_VK_" portion and any underscores
 * removed. For example, the KeyEvent constant DOM_VK_BACK_SPACE becomes
 * BACKSPACE. See the Keymap.keyCodeToFunctionKey object in this module for a
 * complete list of names.
 *
 * A key identifier may also include modifier key prefixes. These prefixes are
 * Alt_, Ctrl_, and Shift_. They are case-insensitive, but if there is more
 * than one, they must appear in alphabetical order. Some key identifiers that
 * include modifiers include "Shift_A", "ALT_F2", and "alt_ctrl_delete". Note
 * that "ctrl_alt_delete" is not legal because the modifiers are not in
 * alphabetical order.
 *
 * Shifted punctuation characters are normally returned as the appropriate
 * character. Shift-2 generates a key identifier of "@", for example. But if
 * Alt or Ctrl is also held down, the unshifted symbol is used instead.
 * We get a key identifier of Ctrl_Shift_2 instead of Ctrl_@, for example.
 *
 * Handler Functions
 *
 * When a handler function is invoked, it is passed three arguments:
 *   1) the HTML element on which the key event occurred
 *   2) the key identifier of the key that was pressed
 *   3) the event object for the keydown event
 *
 * Default Handler
 *
 * The reserved key name "default" may be mapped to a handler function. That
 * function will be invoked when no other key-specific binding exists.
 *
 * Limitations
 *
 * It is not possible to bind a handler function to all keys. The operating
 * system traps some key sequences (Alt-F4, for example). And the browser
 * itself may trap others (Ctrl-S, for example). This code is browser, OS,
 * and locale-dependent. Function keys and modified function keys work well,
 * and unmodified printable keys work well. The combination of Ctrl and Alt
 * with printable characters, and particularly with punctuation characters, is
 * less robust.
 */

// This is the constructor function
function Keymap(bindings) {
    this.map = {};    // Define the key identifier->handler map
    if (bindings) {   // Copy initial bindings into it, converting to lowercase
        for(name in bindings) this.map[name.toLowerCase( )] = bindings[name];
    }
}

// Bind the specified key identifier to the specified handler function
Keymap.prototype.bind = function(key, func) {
    this.map[key.toLowerCase( )] = func;
};

// Delete the binding for the specified key identifier
Keymap.prototype.unbind = function(key) {
    delete this.map[key.toLowerCase( )];
};

// Install this Keymap on the specified HTML element
Keymap.prototype.install = function(element) {
    // This is the event-handler function
    var keymap = this;
    function handler(event) { return keymap.dispatch(event); }

    // Now install it
    if (element.addEventListener) {
        element.addEventListener("keydown", handler, false);
        element.addEventListener("keypress", handler, false);
    }
    else if (element.attachEvent) {
        element.attachEvent("onkeydown", handler);
        element.attachEvent("onkeypress", handler);
    }
    else {
        element.onkeydown = element.onkeypress = handler;
    }
};

// This object maps keyCode values to key names for common nonprinting
// function keys. IE and Firefox use mostly compatible keycodes for these.
// Note, however that these keycodes may be device-dependent and different
// keyboard layouts may have different values.
Keymap.keyCodeToFunctionKey = {
    8:"backspace", 9:"tab", 13:"return", 19:"pause", 27:"escape", 32:"space",
    33:"pageup", 34:"pagedown", 35:"end", 36:"home", 37:"left", 38:"up",
    39:"right", 40:"down", 44:"printscreen", 45:"insert", 46:"delete",
    112:"f1", 113:"f2", 114:"f3", 115:"f4", 116:"f5", 117:"f6", 118:"f7",
    119:"f8", 120:"f9", 121:"f10", 122:"f11", 123:"f12",
    144:"numlock", 145:"scrolllock"
};

// This object maps keydown keycode values to key names for printable
// characters. Alphanumeric characters have their ASCII code, but
// punctuation characters do not. Note that this may be locale-dependent
// and may not work correctly on international keyboards.
Keymap.keyCodeToPrintableChar = {
    48:"0", 49:"1", 50:"2", 51:"3", 52:"4", 53:"5", 54:"6", 55:"7", 56:"8",
    57:"9", 59:";", 61:"=", 65:"a", 66:"b", 67:"c", 68:"d",
    69:"e", 70:"f", 71:"g", 72:"h", 73:"i", 74:"j", 75:"k", 76:"l", 77:"m",
    78:"n", 79:"o", 80:"p", 81:"q", 82:"r", 83:"s", 84:"t", 85:"u", 86:"v",
    87:"w", 88:"x", 89:"y", 90:"z", 107:"+", 109:"-", 110:".", 188:",",
    190:".", 191:"/", 192:"'", 219:"[", 220:"//", 221:"]", 222:"/""
};

// This method dispatches key events based on the keymap bindings.
Keymap.prototype.dispatch = function(event) {
    var e = event || window.event;  // Handle IE event model

    // We start off with no modifiers and no key name
    var modifiers = ""
    var keyname = null;

    if (e.type == "keydown") {
        var code = e.keyCode;
        // Ignore keydown events for Shift, Ctrl, and Alt
        if (code == 16 || code == 17 || code == 18) return;

        // Get the key name from our mapping
        keyname = Keymap.keyCodeToFunctionKey[code];

        // If this wasn't a function key, but the ctrl or alt modifiers are
        // down, we want to treat it like a function key
        if (!keyname && (e.altKey || e.ctrlKey))
            keyname = Keymap.keyCodeToPrintableChar[code];

        // If we found a name for this key, figure out its modifiers.
        // Otherwise just return and ignore this keydown event.
        if (keyname) {
            if (e.altKey) modifiers += "alt_";
            if (e.ctrlKey) modifiers += "ctrl_";
            if (e.shiftKey) modifiers += "shift_";
        }
        else return;
    }
    else if (e.type == "keypress") {
        // If ctrl or alt are down, we've already handled it.
        if (e.altKey || e.ctrlKey) return;

        // In Firefox we get keypress events even for nonprinting keys.
        // In this case, just return and pretend it didn't happen.
        if (e.charCode != undefined && e.charCode == 0) return;

        // Firefox gives us printing keys in e.charCode, IE in e.charCode
        var code = e.charCode || e.keyCode;

        // The code is an ASCII code, so just convert to a string.
        keyname=String.fromCharCode(code);

        // If the key name is uppercase, convert to lower and add shift
        // We do it this way to handle CAPS LOCK; it sends capital letters
        // without having the shift modifier set.
        var lowercase = keyname.toLowerCase( );
        if (keyname != lowercase) {
            keyname = lowercase;    // Use the lowercase form of the name
            modifiers = "shift_";   // and add the shift modifier.
        }
    }

    // Now that we've determined the modifiers and key name, we look for
    // a handler function for the key and modifier combination
    var func = this.map[modifiers+keyname];

    // If we didn't find one, use the default handler, if it exists
    if (!func) func = this.map["default"];

    if (func) {  // If there is a handler for this key, handle it
        // Figure out what element the event occurred on
        var target = e.target;              // DOM standard event model
        if (!target) target = e.srcElement; // IE event model

        // Invoke the handler function
        func(target, modifiers+keyname, e);

        // Stop the event from propagating, and prevent the default action for
        // the event. Note that preventDefault doesn't usually prevent
        // top-level browser commands like F1 for help.
        if (e.stopPropagation) e.stopPropagation( );  // DOM model
        else e.cancelBubble = true;                  // IE model
        if (e.preventDefault) e.preventDefault( );    // DOM
        else e.returnValue = false;                  // IE
        return false;                                // Legacy event model
    }
};

 

 

/**
 * InputFilter.js: unobtrusive filtering of keystrokes for <input> tags
 *
 * This module finds all <input type="text"> elements in the document that
 * have a nonstandard attribute named "allowed". It registers an onkeypress
 * event handler for any such element to restrict the user's input so that
 * only characters that appear in the value of the allowed attribute may be
 * entered. If the <input> element also has an attribute named "messageid",
 * the value of that attribute is taken to be the id of another document
 * element. If the user types a character that is not allowed, the messageid
 * element is made visible. If the user types a character that is allowed,
 * the messageid element is hidden. This message id element is intended to
 * offer an explanation to the user of why her keystroke was rejected. It
 * should typically be styled with CSS so that it is initially invisible.
 *
 * Here is some sample HTML that uses this module.
 *   Zipcode:
 *   <input id="zip" type="text" allowed="0123456789" messageid="zipwarn">
 *   <span id="zipwarn" style="color:red;visibility:hidden">Digits only</SPAN>  *
 * In browsers such as IE, which do not support addEventListener( ), the
 * keypress handler registered by this module overwrites any keypress handler
 * defined in HTML.
 *
 * This module is purely unobtrusive: it does not define any symbols in
 * the global namespace.
 */
(function( ) {  // The entire module is within an anonymous function
    // When the document finishes loading, call the init( ) function below
    if (window.addEventListener) window.addEventListener("load", init, false);
    else if (window.attachEvent) window.attachEvent("onload", init);

    // Find all the <input> tags we need to register an event handler on
    function init( ) {
        var inputtags = document.getElementsByTagName("input");
        for(var i = 0 ; i < inputtags.length; i++) { // Loop through all tags
            var tag = inputtags[i];
            if (tag.type != "text") continue; // We only want text fields
            var allowed = tag.getAttribute("allowed");
            if (!allowed) continue;  // And only if they have an allowed attr

            // Register our event handler function on this input tag
            if (tag.addEventListener)
                tag.addEventListener("keypress", filter, false);
            else {
                // We don't use attachEvent because it does not invoke the
                // handler function with the correct value of the this keyword.
                tag.onkeypress = filter;
            }
        }
    }

    // This is the keypress handler that filters the user's input
    function filter(event) {
        // Get the event object and character code in a portable way
        var e = event || window.event;         // Key event object
        var code = e.charCode || e.keyCode;    // What key was pressed

        // If this keystroke is a function key of any kind, do not filter it
        if (e.charCode == 0) return true;       // Function key (Firefox only)
        if (e.ctrlKey || e.altKey) return true; // Ctrl or Alt held down
        if (code < 32) return true;             // ASCII control character

        // Now look up information we need from this input element
        var allowed = this.getAttribute("allowed");     // Legal chars
        var messageElement = null;                      // Message to hide/show
        var messageid = this.getAttribute("messageid"); // Message id, if any
        if (messageid)  // If there is a message id, get the element
            messageElement = document.getElementById(messageid);

        // Convert the character code to a character
        var c = String.fromCharCode(code);

        // See if the character is in the set of allowed characters
        if (allowed.indexOf(c) != -1) {
            // If c is a legal character, hide the message, if any
            if (messageElement) messageElement.style.visibility = "hidden";
            return true; // And accept the character
        }
        else {
            // If c is not in the set of allowed characters, display message
            if (messageElement) messageElement.style.visibility = "visible";
            // And reject this keypress event
            if (e.preventDefault) e.preventDefault( );
            if (e.returnValue) e.returnValue = false;
            return false;
        }
    }
})( ); // Finish anonymous function and invoke it.

 

5.2.4.12. 加載事件 onload Event
onload回在文檔完全加載完成后運行

一個跨平台的版本

function runOnLoad(f) {
    if (runOnLoad.loaded) f( );    // If already loaded, just invoke f( ) now.
    else runOnLoad.funcs.push(f); // Otherwise, store it for later
}

runOnLoad.funcs = []; // The array of functions to call when the document loads
runOnLoad.loaded = false; // The functions have not been run yet.

// Run all registered functions in the order in which they were registered.
// It is safe to call runOnLoad.run( ) more than once: invocations after the
// first do nothing. It is safe for an initialization function to call
// runOnLoad( ) to register another function.
runOnLoad.run = function( ) {
    if (runOnLoad.loaded) return;  // If we've already run, do nothing

    for(var i = 0; i < runOnLoad.funcs.length; i++) {
        try { runOnLoad.funcs[i]( ); }
        catch(e) { /* An exception in one function shouldn't stop the rest */ }
    }

    runOnLoad.loaded = true; // Remember that we've already run once.
    delete runOnLoad.funcs;  // But don't remember the functions themselves.
    delete runOnLoad.run;    // And forget about this function too!
};

// Register runOnLoad.run( ) as the onload event handler 
 for the window
if (window.addEventListener)
    window.addEventListener("load", runOnLoad.run, false);
else if (window.attachEvent) window.attachEvent("onload", runOnLoad.run);
else window.onload = runOnLoad.run;

5.2.4.13. 合成事件 Synthetic Events

5.2.5. cookie
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *


6. JS庫:prototype

6.1. $()等價getElementById()
$() 方法是在DOM中使用過於頻繁的 document.getElementById() 方法的簡寫,這個方法返回參數傳入的id的那個元素。

你可以傳入多個id作為參數然后 $() 返回一個帶有所有要求的元素的一個 Array 對象。

    function test2()
    {
        var divs = $('myDiv','myOtherDiv');
        for(i=0; i<divs.length; i++)
        {
            alert(divs[i].innerHTML);
        }
    }
</script>
<div id="myDiv">
        <p>This is a paragraph</p>
</div>
<div id="myOtherDiv">
        <p>This is another paragraph</p>
</div>

<input type="button" value=Test2 onclick="test2();">

6.2. $F()返回輸入控件的值

<script>
    function test3()
    {
        alert(  $F('userName')  );
    }
</script>

<input type="text" id="userName" value="Joe Doe"><br> 
<input type="button" value=Test3 onclick="test3();"><br>

6.3. $A()參數轉Array
這個方法加上對Array類的擴展,可以很容易的轉換或者復制任意的列舉列表到Array對象, 一個被推薦使用的用法就是轉換DOM的NodeLists到一個普通的數組里,可以被更廣泛高效的使用, 看下面的例子。

<script>
    function showOptions(){
        var someNodeList = $('lstEmployees').getElementsByTagName('option');
        var nodes = $A(someNodeList);

        nodes.each(
        function(node){
        alert(node.nodeName + ': ' + node.innerHTML);
        }
        );
    }
</script>

<select id="lstEmployees" size="10" >
    <option value="5">Buchanan, Steven</option>
    <option value="8">Callahan, Laura</option>
    <option value="1">Davolio, Nancy</option>
</select>

<input type="button" value="Show the options" onclick="showOptions();"

6.4. $H()轉類似聯合數組的Hash對象
$H()方法把對象轉化成可枚舉的貌似聯合數組Hash對象。

<script>
    function testHash()
    {
        //let's create the object
        var a = {
            first: 10,
            second: 20,
            third: 30
            };

        //now transform it into a hash
        var h = $H(a);
        alert(h.toQueryString()); //displays: first=10&second=20&third=30
    }

</script>
==$R()簡單的遍歷 == 用方法$R()方法是new ObjectRange(lowerBound, upperBound, excludeBounds)的一個簡單快捷的使用方式。

<script>
    function demoDollar_R(){
        var range = $R(10, 20, false);
        range.each(function(value, index){
            alert(value);
        });
    }

</script>

<input type="button" value="Sample Count" onclick="demoDollar_R();" >

6.5. Try.these()嘗試直到一個成功
方法Try.these() 方法使得實現當你想調用不同的方法直到其中的一個成功正常的這種需求變得非常容易, 他把一系列的方法作為參數並且按順序的一個一個的執行這些方法直到其中的一個成功執行,返回成功執行的那個方法的返回值。

在下面的例子中, xmlNode.text在一些瀏覽器中好用,但是xmlNode.textContent在另一些瀏覽器中正常工作。 使用Try.these()方法我們可以得到正常工作的那個方法的返回值。

<script>
function getXmlNodeValue(xmlNode){
    return Try.these(
        function() {return xmlNode.text;},
        function() {return xmlNode.textContent;)
        );
}
</script>
== Ajax.RequestXML響應==

如果你不使用任何的幫助程序包,你很可能編寫了整個大量的代碼來創建XMLHttpRequest對象並且異步的跟蹤它的進程,然后解析出響應 然后處理它。當你不需要支持多於一種類型的瀏覽器時你會感到非常的幸運。

為了支持 AJAX 功能。這個包定義了 Ajax.Request 類。

假如你有一個應用程序可以通過url http://yoursever/app/get_sales?empID=1234&year=1998與服務器通信。它返回下面這樣的XML響應。

<?xml version="1.0" encoding="utf-8" ?>
<ajax-response>
<response type="object" id="productDetails">
<monthly-sales>
<employee-sales>
<employee-id>1234</employee-id>
<year-month>1998-01</year-month>
<sales>$8,115.36</sales>
</employee-sales>
<employee-sales>
<employee-id>1234</employee-id>
<year-month>1998-02</year-month>
<sales>$11,147.51</sales>
</employee-sales>
</monthly-sales>
</response>
</ajax-response>
用 Ajax.Request對象和服務器通信並且得到這段XML是非常簡單的。下面的例子演示了它是如何完成的。

<script>
function searchSales()
{
var empID = $F('lstEmployees');
var y = $F('lstYears');
var url = 'http://yoursever/app/get_sales';
var pars = 'empID=' + empID + '&year=' + y;
var myAjax = new Ajax.Request( url, { method: 'get', parameters: pars, onComplete: showResponse });

}
function showResponse(originalRequest)
{
//put returned XML in the textarea
$('result').value = originalRequest.responseText;
}
</script>
<select id="lstEmployees" size="10" onchange="searchSales()">
<option value="5">Buchanan, Steven</option>
<option value="8">Callahan, Laura</option>
<option value="1">Davolio, Nancy</option>
</select>
<select id="lstYears" size="3" onchange="searchSales()">
<option selected="selected" value="1996">1996</option>
<option value="1997">1997</option>
<option value="1998">1998</option>
</select>
<br><textarea id=result cols=60 rows=10 ></textarea>
你注意到傳入 Ajax.Request構造方法的第二個對象了嗎? 參數{method: 'get', parameters: pars, onComplete: showResponse} 表示一個匿名對象的真實寫法。他表示你傳入的這個對象有一個名為 method 值為 'get'的屬性,另一個屬性名為 parameters 包含HTTP請求的查詢字符串,和一個onComplete 屬性/方法包含函數showResponse。

還有一些其它的屬性可以在這個對象里面定義和設置,如 asynchronous,可以為true 或 false 來決定AJAX對服務器的調用是否是異步的(默認值是 true)。

這個參數定義AJAX調用的選項。在我們的例子中,在第一個參數通過HTTP GET命令請求那個url,傳入了變量 pars包含的查詢字符串, Ajax.Request 對象在它完成接收響應的時候將調用showResponse 方法。

也許你知道, XMLHttpRequest在HTTP請求期間將報告進度情況。這個進度被描述為四個不同階段:Loading, Loaded, Interactive, 或 Complete。你可以使 Ajax.Request 對象在任何階段調用自定義方法 ,Complete 是最常用的一個。想調用自定義的方法只需要簡單的在請求的選項參數中的名為 onXXXXX 屬性/方法中提供自定義的方法對象。 就像我們例子中的 onComplete 。你傳入的方法將會被用一個參數調用,這個參數是 XMLHttpRequest 對象自己。你將會用這個對象去得到返回的數據並且或許檢查包含有在這次調用中的HTTP結果代碼的 status 屬性。

還有另外兩個有用的選項用來處理結果。我們可以在onSuccess 選項處傳入一個方法,當AJAX無誤的執行完后調用, 相反的,也可以在onFailure選項處傳入一個方法,當服務器端出現錯誤時調用。正如onXXXXX 選項傳入的方法一樣,這兩個在被調用的時候也傳入一個帶有AJAX請求的XMLHttpRequest對象。

我們的例子沒有用任何有趣的方式處理這個 XML響應, 我們只是把這段XML放進了一個文本域里面。對這個響應的一個典型的應用很可能就是找到其中的想要的信息,然后更新頁面中的某些元素, 或者甚至可能做某些XSLT轉換而在頁面中產生一些HTML。

在1.4.0版本中,一種新的事件回傳外理被引入。如果你有一段代碼總是要為一個特殊的事件執行,而不管是哪個AJAX調用引發它,那么你可以使用新的Ajax.Responders對象。 
假設你想要在一個AJAX調用正在運行時,顯示一些提示效果,像一個不斷轉動的圖標之類的,你可以使用兩個全局事件Handler來做到,其中一個在第一個調用開始時顯示圖標,另一個在最后一個調用完成時隱藏圖標。看下面的例子。

<script>
var myGlobalHandlers = {
onCreate: function(){
Element.show('systemWorking');
},
onComplete: function() {
if(Ajax.activeRequestCount == 0){
Element.hide('systemWorking');
}
}
};
Ajax.Responders.register(myGlobalHandlers);
</script>
<div id='systemWorking'><img src='spinner.gif'>Loading...</div>
更完全的解釋,請參照 Ajax.Request 參考 和 Ajax選項參考。

MoinMoin PoweredPython PoweredValid HTML 4.01 
推薦使用支持W3C標准的瀏覽器進行閱讀,獲得最佳頁面效果,謝絕IE的混亂解析!   Searching all CPUG sites and mailist::
  
 Web 
getACL = 0.006s getPageList = 0.204s loadLanguage = 0.005s load_multi_cfg = 0.003s run = 0.364s send_page = 0.112s send_page_content = 0.052s total = 0.378s 

 

原文地址  http://www.th7.cn/web/ajax/201411/67496.shtml


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM