我的相片
劍俠鼻唄
如果一個人會不依著同伴的步伐前進,有可能是因為他聽到了另一種鼓聲。
檢視我的完整簡介

2006年6月1日 星期四

網頁的靈魂-JavaScript

網頁因為有Script語言,而有了行動力。當然跟動態網頁如asp/php/jsp...等,仍無法比擬,但如JavaScript或VBScript等Script語言,能在client端即實現部分的行動力(流程控制的能力),巳相當不容易(應該說是相當厲害),雖然Script語言似乎著重在特效方面。尾田榮一郎在海賊王中將影子描述成「人的靈魂」之一,若照這種構想,稱它為網頁的靈魂,應該也稱得上吧。或說Script是......網頁的...影子...呵呵。

當然,這只是布魯克個人方便查閱之用。
網上的教學文章巳有一大票了,這並非教學文章,所以並不注重在章節的編排及講解,何況布魯克也不敢妄稱教學,這只是布魯克個人的足跡記錄。

第0章

零.註解:
(1)單行註解://這是註解
(2)多行註解:/*這是註解*/

一.宣告: 用<script>標籤嵌在HTML 中。

1.格式:
<script>
JavaScript格式碼...
</script>

2外部嵌入:用<script>敍述標籤的src屬性從外部滙入JavaScript檔。

JavaScript程式碼若很大時,可以單獨放在一個檔案中,副檔名為js。再用<script>標籤的src屬性指明JavaScript的外部檔案所在位置。<script>標籤的langage屬性用以指明是哪種敍述語言,例如JavaScript或是VbScript。

(1)外部嵌入的格式:
<script langage="javascript" src="...XXX.js">
</script>

♨一般為防有瀏覽器不支援,在宣告JavaScript時都會加上註解。如:
<script language="JavaScript">
<!--
JavaScript格式碼...
-->
</script>

♨一般函數和事件處理函數會放在<head>部分,而呼叫函數的程式碼會放在<body>。
此舉是為保證執行的程式碼呼叫相關函數時,該函數的程式碼已被載入。因為如函數等,被瀏覽器讀到時,會被載入和儲存,但不會被執行。但在<body>內的程式碼會馬上被執行。
若重複率太高的程式碼,因為會重複出現在數份的html文件中,重複撰寫就太麻煩了(就算是copy也很累),而且佔太多空間,所以正常人都會將之獨立成一個外部檔案,在網頁中再去連結。


二.保留字(reserved word;保留的關鍵字)

1.javascript的保留字
break
case
catch
continue
default
delete
do
else
false
finally
for
function
if
in
instanceof
new
null
return
switch
this
throw
true
try
typeof
var
void
while
with


2.ECMA擴充的保留字
abstract
boolean
byte
char
class
const
debugger
double
enum
export
extends
final
float
goto
implements
import
int
interface
long
native
package
private
protected
public
short
static
super
synchronized
throws
transient
volatile

♨javascript已定義的廣域變數與函數名稱等等,也應避免使用.

三.跳脫字元(反斜線;「\」)

跳脫字元表示
\oNUL字元
\b倒退鍵(Backspace鍵)
\t水平定位(Tab鍵)
\n換行
\v垂直定位
\f下一頁
\r游標歸位
\"雙引號(顯示「"」)
\'單引號(顯示「'」)
\\反斜線(顯示「\」)
\xXX由兩位數的十六進位數XX定義的Latin-1字元
\uXXXX由四位數的十六進位數XXXX定義的Latin-1字元
\XXX由一到三位數的八進位數XXX定義的Latin-1字元
(XXX範圍必須是0~377,且八進位不建議使用.)


四.其他javascript相關的寫作風格。

1.聽說javascript的大小寫有分別(跟java一樣)
2.聽說敍述末的分號「;」非必要(聽說它會自動加),但最好自己是加一加算了,以免出錯。
(敍述結束符號「;」,由自己來加也比較能掌控狀況,如多個簡短的敍述,要全寫在同一行,若分號由自己加,就比較容易分辨,他人也較易分辨。)
3.太長的程式碼,基於編排的需要也可以分成二列。所以也可能看到下面這種程式碼。
document.write\
("布魯克");
♨老實說布魯克也是頭次聽到有這種東東。
上述的反斜線「\」,聽說寫JScript沒有這種情況(跟語言有關?還是跟瀏覽覽器有關?),一般也不會有這種情況,都是直接enter的。


第一章 資料型態

一.基本型態

1.數值:整數和浮點數.

(1)據說javascript的所有數值都以浮點數表示,並不分別整數和浮點數.
(2)浮點數可用指數記號表示法.「E或e」
(3)能辨識十六進位的整數.
<1>十六進進:以「0X」開頭。
<2>八進位:以「0」開頭。
(4).特殊的數值:


#JavaScript的一些特別數值
數值定義備註
Number.NaN
(NaN)
非數字的特殊值(比較)
(參考)
Number.POSITIVE_INFINITY
(Infinity)
無限大的特殊值(比較)

Number.NEGATIVE_INFINITY
(-Infinity)
無限小的特殊值
Number.MAX_VALUEJS能表示的最大數字
Number.MIN_VALUEJS能表示的最小數字(最接近0的)

♨1.Infinity:若一個數值比JavaScript所能表示的最大值還大,結果就是無限大.反之就是無限小,表示成「-Infinity」.
Infinity:全域屬性,用來存放表示正無大的特殊值(Number.POSITIVE_INFINITY),用for-in無法窮舉Infinity屬性,用delete運算子無法刪除,在ECMAScript v1以後,可以由全域變數Infinity取得Number.POSITIVE_INFINITY,負無窮(-Infinity)亦同.
注意到,Infinity並不是常數,它可以被指定為其他值,但Number.POSITIVE_INFINITY是常數

2.NaN:全域屬性,指向一非數字的特殊值(Number.NaN),用for-in無法窮舉Infinity屬性,用delete運算子無法刪除,如果數值的運算產生一個末定義的結果或錯誤時,如某些算術運算的結果不是數字,就會傳回「NaN」意指"非數字"(not-a-number).
值在Number.NaN,在ECMAScript v1以後,可以由全域變數NaN取得
注意到,NaN並不是常數,它可以被指定為其他值,要判斷一數字是否NaN要用isNaN(),因為無法用運算子==,===來判斷NaN.


2.字串:必需用雙引號「"」或單引號「'」括起來.(不然怎麼知道是字串呢?)

3.布林值:true或false.

4.空值:null.
null就是「沒有值」(no value),是資料型態Null的唯一合法值.
若試圖操作沒有定義的變數,就會傳回一個null值.亦即變數的資料值是null,表示它沒有包含任何其他合法的數值,字串,布林值,陣列,物件.

若一個物件用判別式write出來,顯示null,表示它不是一個物件。
(參考第三章,三.判定變數是否存在)

5.未定義值:undefined
一個變數有宣告,但卻不曾指定資料值。就會出現undefined值。
或是一個物件屬性,沒有指定值,也會出現undefined值。

(♨聽說,若試圖操作沒有定義的變數,就會傳回一個undefined值(未定義值),undefined值和null值並不相同.不過等號運算子「==」會把兩者判為相等.)
♨基本的資料型態就只有三種:數值、字串、布林。其實布魯克還很懷疑,是否有必要分別資料型態?往後就會看到,其實JS所有的東西都是物件,而且assign時也不必指明資料型態,不管指定什麼資料型態,變數都會接受,只要指定的資料是什麼型態,變數就是什麼型態。所以布魯克才覺得奇怪,是否有必要分別資料型態。


二.參考型態
1.函數。2.物件。3.陣列。

也就是說物件,陣列,函數等,因為資料太大(或說我們根本無法準確地知道它的大小),所以在記憶體是儲存一個參考(reference)而已,它是指向(refer;參考)到一資料值的所在位址,並不是資料本身。(後再詳述)

♨1.因為JavaScript以有限個浮點數表示無限的實數,所以我們使用實數時,JavaScrit所表示的數值,其實是真實數值的近似值.
2.要用負數當然是加個負號「-」,不過負號屬運算子,不算數值本身的一部分
3.八進位也能用,但最好不要,容易錯亂.因為我們不知道它會辨識成十進位還是八進位
4.JavaScrit不像java,整數還分龍吟嘯擺(long,int,short,byte)浮點數還分單雙(double,float))
5.java或C裡,還有字元資料型態char,JavaScrit也沒有.它到底需不需要分別資料型態?布魯克也搞不懂.
6.資料的連接用加號「+」


三.資料型態的轉換

(一)

運算式處理模式
數字和字串相加數字會轉換成字串
布林和字串相加布林會轉換字串
布林和數字相加布林會強制轉成數字


(二)資料型態的轉換函數
JS有內建一些函數可以轉換資料型態。

1.parseFloat()方法
將字串開頭的數字轉成浮點數,若開頭不是數字,傳回NaN(Not a number)。

parseFloat()依字面上的意思就是:解析成浮點數.這個函數的功用就是把字串轉成數字.
當然,想也知道,字串是不可能轉成數字的,或者說,並非所有的字串都能轉成數字,parseFloat()的本意是“將數字型態的字串轉回數字”,所以當parseFloat()接收到要轉成數字的字串時,就會開始對字串進行解析,若遇到非數字型態的字串時,程序就會停止解析,並將結果傳回,所以,若字串一開始便不是數字型態的字串開頭,程序就會停止,並傳回NaN(非數字).
要檢測NaN,可以用isNaN().
♨聽說,在JS1.0中parseFloat()遇到無法解析成數字的字串會傳回0

a.用法,parseFloat("字串")
b.參數,要轉成浮點數的字串
c.回傳值,第一個數字型態的字串轉成浮點數傳回,若遇到非數字型態的字串,就傳回NaN(Not a number)。
d.例

parseint()結果備註
parseFloat("3.2")3.2字串開頭為浮點數
parseFloat("小調3.2丁")NaN字串開頭不是浮點數


2.parseint()方法
可將字串開頭的數字轉換成整數,若字串没有數字就會傳回NaN(Not a number)。
parseFloat的兄弟,parseint()可以將字串轉成整數,當parseint()接收到要轉成整數的字串時,就會開始對字串進行解析,若遇到非數字型態的字串時,程序就會停止解析,並將結果傳回,所以,若字串一開始便不是數字型態的字串開頭,程序就會停止,並傳回NaN(非數字).
要檢測NaN,可以用isNaN().
♨聽說,在JS1.0中parseFloat()遇到無法解析成數字的字串會傳回0
a.用法,
parseint("字串")
parseint("字串",n)
b.參數,字串參數是要轉換成整數的字串,n是個數字,表示基數,以指定轉換成10進位,16進位或八進位。所以第二個參數是數值10、8、16。若n省略或n值為0,則預設是以10為基數(10進位),
若n<2或36<n,parseint()會傳回NaN.
若字串是0x開頭,parseint()會自動將其餘數字型態的字串轉成16進位的整數,
若字串是0開頭,parseint()會自動將其餘數字型態的字串轉成8進位的整數,
若字串是1~9的整數開頭,parseint()會自動將其餘數字型態的字串轉成10進位的整數,
♨若字串開頭的數字型態字串,並不明確,如parseint("010")則基數就不一定了,要看系統當時自動選舉是什麼
c.回傳值,第一個數字型態的字串會依指定的基數轉成整數傳回,遇到非數字型態的字串,或基數是1,或超過36就傳回NaN(Not a number)。
d.例,


parseint()結果備註
parseint("3刀流")3字串開頭為數字是整數3
parseint("3.2")3浮點數型的字串,第一個數字是3.2,只取出整數
parseint("小調3丁")NaN字串開頭不是數字
parseint("18ff值",16)6399將字串轉成16進位值的結果
parseint("18ff值",10)18將字串轉成轉成10進位值的結果
parseint("18ff值",8)1將字串轉成轉成8進位值,遇到8又進位為1。


3.eval()方法
能把字串當作運算式,傳回一個運算式字串的運算結果


eval()結果備註
eval("3+3*2")9算式運算式的運算結果
eval("3>2")true邏輯運算式的運算結果
eval("intA=30")30指定敘述


4.typeof()運算子
可以判斷變數的資料型態,判讀變數是string、number、boolean、undefined、object。所以它的參數是個變數。
但是,如果變數裡的值是null,typeof()會判讀成object。

第二章 運算子


運算子作用
()小括號
-、++、--、!-(負號)++(遞增)--(遞減)!(邏輯運算子NOT)
+、 -、*、/、%算術運算子,加減乘除取餘數(當然先乘除取餘數後加減)
<<、 >>、 >>>位元運算子左移、右移和補0的右移
>、>=、<、<=
==、!=
比較(關係)運算子大於、大於等於和不等於
&、^、、~位元運算子,AND,XOR,OR,NOT(JS裡好像沒有NOT「~」)
&&、(、!)邏輯運算子,AND,OR(,NOT)
?:條件運算子若則(if else)。a?b:c。A為真嗎?若a為真取b否則取c
=(、op=)指定運算子



第三章 識別字

識別字就是用來命名變數,函數,迴圈等等,茲以識別的字.
識別字與保留字是一樣的,只是保留字已被作者用了(作者用了我們當然不能用),識別字與保留字統稱為關鍵字,即亦除了保留字以外我們自己命名的關鍵字就是識別字.

一.識別字的命名規則:1.英文字母(「a~z」),2.底線(「_」),3.數字(「0~9」),4.錢(「$」)。
♨第一個字元不能是數字(和java一樣,聽說是為了方便系統容易分辨識別字和數值)

二.變數

1.變數宣告:用關鍵字var宣告

格式:var 變數名;

(1)個別變數宣告
如:var a ; var b;

(2)一次宣告多個變數
如:var a, b;

聽說不宣告也可以啦,因為javascript看到有奇奇怪怪的東西被指定資料值,它就會以為那是變數,自動幫你宣告,所以也被稱是鬆散型的語言(loosely typed language)(這時該變數是一廣域變數.)
大概就是這樣了,反正宣告就沒錯,記得區域變數最好先初始化就可以了.若試圖操作一個未宣告的變數,就會產生錯誤,所以不用怕.

(3)不宣告直接指定

如:strNo="0123";


1.第一種未宣告的變數是,變數沒宣告,直接指定,則如上所述javascript會愉愉幫你宣告.
2.第二種未宣告的變數是,變數沒宣告,又沒指定,此時若試圖引用這個變數就會產生錯誤.(變數沒宣告,又沒指定,表示這個東西根本就用不到,javascript根本不知道那是什麼東西,誰知道是不是哪個人不小心按到,這種根本不存在的變數,引用就會出現錯誤)
3.第三種變數是,變數宣告了,卻沒指定.這種宣告了,卻從不去用的東西稱作「未指定變數」(unassigned).它有存在,但從沒用到,則存取這種變數時會得到它的預設值---「未定義值」(undfined)


2.區域變數VS.全域變數


區域變數在函數內宣告的變數,變數只能在函數內調用,函數以為的程式碼無法存取
全域變數在函數外宣告的變數,函數外或函數內的程式碼都可以存取。


3.判定變數是否存在

要判斷一個變數是否存在,有window物件可用(所有的變數,都屬window屬性所管),或可以直接寫一個判斷式。如下:
if(a){
document.write("變數a存在<br>");

else
document.write("變數a不存在<br>");
}



if(window.a){
document.write("變數a存在:"+window.a+"<br>");

else
document.write("變數a不存在:"+window.a+"<br>");
}
♨不存在的變數write出來看,就能發現顯示undefined。
由此例可知,一個物個的屬生若不存在,也是undefined。


第四章 結構流程

一.循序結構:一行一行往下執行的結構。

二.選擇結構:由許多「決策」所組合而成的結構。

1.if敍述:

if(判斷式){
敍述;
}

♨額外去做的事。
敍述若只有一列,很多人都會把大括號省略


2.if-else敍述:

if(判斷式){
敍述;
}else{
敍述;
}

♨當然敍述若只有一列,大括號就可以省略。如:
if(memberSex=="female")
document.write("羅賓、娜美");
else
document.write("魯夫、索隆、騙人布、香吉士、佛朗基、布魯克");




3.switch敍述:

switch(判斷式){
case 1://每個case就相當於==。所以後面不一定是數值,字串也可以。
敍述;
break;
case 2:
敍述;
break;
case 3:
敍述;
break;
}

♨switch和巢狀的if-else敍述是一樣的.
if(判斷式){
敍述;
}else if(判斷式){
敍述;
}else{
敍述;
}


三.迴圈結構(loop):可重覆執行某個動作的結構。


1.for迴圈
for(迴圈參數初始值;判斷式;設定增減量){
敍述;
}

2.while迴圈
while(判斷式){
敍述;
(設定增減量;)
}

3.do-while迴圈

do{
敍述;
}while(判斷式);

♨上述迴圈中的判斷式,指的是終止條件


四.其他和迴圈相關的東東

1.?:運算子

a?b:c和if else敍述是一樣的,相當於簡潔式。
「?」相當於if,「:」相當於else。如:

strHours=(dHour>=12)?"PM":"AM";


2.for-in敍述
運作很像for loop,可以用來顯示一物件的所有屬性。

for(變數 in 物件){
}
♨參考第六章一些和物件相關的東東

3.break指令和continue指令

break指令:能強迫終止迴圈,會跳出迴圈,若是巢狀迴圈,會跳回到上一層迴圈。
continue指令:能強迫迴圈繼續執行(再回到迴圈前頭),但continue指令後面的敍述不會被執行。

第五章 函數

1.函數是為執行一特定任務,而使用一連串敍述的集合(稱作程序;Procedure)。包含參數、敍述、關鍵字return。
2.參數不一定要有。例如我們可以建立一個專門用來輸出相同訊息的函數,如下:
function writeWelcome(){
document.write("歡迎光臨!今天是X月X日,農曆X月X日,忌罵人,宜灑錢。祝錢散人安樂!");
}
3.return是用來回傳值(函數執行後的結果)的。函數執行遇到return就會終止,而跳出,也不一定要有,但在判斷式常見多個return。也就是說遇到return後,函數就算是終止了,因為巳有結果了,其後的其他敍述更不會被執行。
4.函數在宣告後,只會被載入及儲存,但不會自動執行,函數只有在被呼叫時,才會執行。

♨聽說JS所有的資料型態都是物件,以這種角度而言,函數(也可看作物件)可以視為一種全域方法

一.函數宣告:
1.函數宣告-關鍵字function

function 函數名(參數,參數,...){
敍述;
return;
}


2.Function()建構式

Function("參數","參數",...,"敍述;")♨有引號喔

3.匿名函數

function (參數,參數,...){
敍述;
return;
}

4.遞迴函數
就是在函數中,呼叫函數自己本身的一種函數。

如下計算階層的函數
function factorial(X){
if (X<=1)
return 1;

return X*factorial(X-1); }

function factorial(n){
if (n==0n==1)
return 1;
else
return n*factorial(n-1);
}
♨據說遞迴只要超過太多層(如100層)就會產生錯誤。

5.巢狀函數
就是在宣告函數時,在函數主體內再宣告函數。

如下畢式定理的函數
function h(a,b){
function square(X){return X*X;}
return Math.sqrt(square(a)+square(b));
}
♨Function()建構子的參數聽說是字串,最後一個參數是放函數主體敍述的。其實Function()建構子和匿名函數,都是不具名的函數。
宣告(定義)函數的目的,只是宣告一個函數的名稱,及定義它在被呼叫時該執行的程序步驟。函數只有在被呼叫時才依我們所呼叫的參數而執行。
但因為有時函數的名稱根本不重要,特別是這個函數很短,或是這個函數只用到一次的時候,還要去宣告命名就太麻煩了,這種匿名函數具有函數的功能,而且也能當成運算式的一部分,可以直接用。

2.函數既然可以指定給變數,所以也可以->指定給陣列->當成參數傳出去->指定給物件的屬性



二.傳值呼叫與傳址呼叫

簡單說,


傳值就是確實傳出變數裡的值。
所以在值傳出後,系統會自動再配置一個記憶體空間以儲存值。
因此函數中更改了變數值(區域變數),對原變數並没有影響(全域變數)。
傳址就是就是傳出變數裡所載的記憶體位置。
所以若在函數入更改了變數值,原變數的值也會被更動。
♨參考傳值呼叫VS.傳址呼叫測試的結果


一般而言,基本資料型態如數字、字串、布林,都是傳值。
物件、陣列、函數等參考型態都是傳址。(參:第一章第二節參考型態)

第六章 物件

物件是屬性(property;成員變數)、方法(method;成員函數)、事件的集合。
簡單說就是資料和處理資料的函數所集結起來的一個抽象的物體。
(♨上述“事件”是布魯克在網上看到某網友的說法,覺得有道理而加上去的,其實處理事件的就是函數嘛)

有些語言,被稱為物件導向的語言(Object-oriented Language),一般都具有封裝(encapsulation)、繼承(inheritance)、多形(polymorphism),等等特色。有些人認為,若用嚴格的物件導向語言如java的標準來看,javascript並不能算是物件導向,而認為其是一個物件基礎的語言(Object-based)。

1.封裝:就是將資料和函數建立成一個物件的技術。(要定義物件是使用「類別」這種抽象的資料型態)
2.繼承:就是定了一張類別後,其他的類別能擁有和衍用這個類別的屬性和方法。
3.多形:就是傳說中的「同名異式」,繼承一個類別後,我們可以擴充這個類別的同名方法,以處理不同的資料型態。這樣就不必另外再寫一張類別,以針對不同的資料型態建立不同的類別。因為方法的名稱相同,只是內容不一樣,所以又稱同名異式。


一.定義物件-關鍵字function

要使用物件之前要先定義物件的原型,也就是類別。
定義物件是使用寫函數的方式,用關鍵字function去定義一個函數,在此函數中再去定義屬性及方法。
屬性就是變數,用以儲存要操作的值。
方法就是函數,用來操作資料值的。

♨因為調用一個物件之前,該物件必須存在(不存在的東東怎麼調用呢?)
2.this關鍵字:this指的就是當前物件之意


1.定義物件
function 類別名(參數,參數,...,參數){
this.屬性名稱=參數;
this.屬性名稱=參數;
this.屬性名稱=參數....;

this.方法名稱=函數名稱;
this.方法名稱=函數名稱;
this.方法名稱=函數名稱;//♨指明函數名即可,没有小括號。
.
.
.
function 函數名稱(){//♨方法具體定義在這裡。

}

this.方法名稱=function(){//♨或直接把函數塞進去。

}

}

二.建立物件---new運算子

定義完物件後,即可用new運算子建立物件。用new生出來的物件,稱作實體物件(實例物件;instance object)。因為定義完的物件原型(類別),作用就像一張藍圖一般,依據這個類別,可以產生無數個物件的實體。

1.在new後面加上物件名稱(或任一建構式名稱)就可以了,new就是用來物件化的運算子。

如:
var (實體)物件名稱 = new 類別(/物件原型)名稱(參數,參數,...,參數);

也就是說(實體)物件名稱,其實就是個變數嘛。new出一個實體物件後,指定在一個變數中,此時這個變數就會自動轉換成一個物件。
♨以下稱實體物件為「物件」(或副本),物件原型稱為「類別」(或物件)。
說仔細點,也就是只有物件原型和實體物件二種概念啦,但一般而言,大家描述這二種東西時,說法不會完全一樣,只說物件,別人搞不清楚是指原型還是實體,因為JS没有「類別」這種資料型態。
現在定義一下,為方便區別,往後在同一段話裡面,「類別」-「物件」,「物件」-「副本」。這兩種描述不會同時出現。類別和物件同時出現,這個物件指的是實體物件。物件和副本同時出現,這個物件是指物件原型。


2.新增物件屬性
在任何時候,我們都可以為任一個物件增加屬性,也就是說,就算我們在建立物件時没有指定屬性值,也可以在建立物件後才去指定。

物件.屬性.屬性....屬性=資料值;

♨為任一個物件增加屬性,增加的屬性只限該物件上,與該物件的類別無關。
比如A類別的物件a1及a2。在a2增加了屬性,該屬性就只有a2擁有,A以及a2以外的其他同類物件如a1並不會改變。
或一般都會在建立物件時指定屬性值。

var 變數=new 類別名("屬性值","屬性值","屬性值",...,"屬性值");


2.1.prototype物件.(♨可先跳過,看完本章與物件相關的東東再看。)

聽說在JS1.1之後,所有的物件都有一個prototype屬性。prototype本身是個物件,prototype物件的屬性會被所有實體物件所繼承。不論物件是否巳實體化,我們都可以使用prototype屬性擴充任一內建或自訂物件的屬性和方法。和expando屬性不同,只能針對特定的實體物件擴充。(expando聽說是IE5.0以後支援的)
♨似乎任何時候擴充都可以,要調用該成員之前有擴充指定即可。在<head>或是在<body>擴充都有看過,但一般都會在<head>擴充指定,和函數一樣,以保證在調用到該成員時,其巳經被載入。
♨聽說JS只允許實體物件使用prototype,不曉得是指什麼?是內建的還是自訂的?還是所有的實體
待查,曾經生出個實體調動prototype卻無法擴充,但用類別卻可以,靠javascript怎麼那麼麻煩?prototype用法還要再查


2.1.1.用prototype物件擴充自訂物件的成員:

物件(/類別).prototype.屬性名=屬性值;
物件(/類別).prototype.方法名=函數名;♨没有括號

若是類別,則所有該類別的物件都會新增上述的成員。

2.1.2.用prototype物件擴充內建物件的成員:

內建物件(/類別).prototype.屬性名=屬性值;
內建物件(/類別).prototype.方法名=函數名;♨没有括號

♨JS內建的函數至少有10種,後述。
如:我們自訂一個函數叫StrReverse();能把輸出的字串顛倒過來,由後面輸出。
//擴充物件方法
String.prototype.reverse=StrReverse;
//建立內建字串物件
var message=new String("步出地獄的風采");
//則任何時候我們都可以調用reverse這個方法
message.reverse();


2.1.3.用prototype物件擴充的成員,是一個物件當然也没問題

物件.prototype=new 類別();

但上述的寫法,因為没有指明是哪個屬性,此時該物件會繼承擁有另一個物件的所有成員。

♨如:
//定義一個位置類別
function position(x,y){
this.x=x;
this.y=y;
}
//定義一個圓類別
function circle(r){
this.r=r;
this.info=showCircle;

function showCircle(){
var area=this.pi*this.r*this.r;
document.write("半徑:"+this.r+"<br/>");
document.write("座標:("+this.x+","+this.y+")<br/>");
vdocument.write("面積:"+area+"<br/>");
}
}
//新增成員
circle.prototype.pi=3.14159;
//過繼位置物件成員到圓物件
circle.prototype=new position();

//生出一個圓
var myCircle=new circle(3);
//指定物件屬性
with(myCircle){
x=6;
y=20;
}
//調用物件方法
myCircle.info();


3.調用物件屬性

(1)物件.屬性.屬性....屬性
(2)物件["屬性"]♨注意喔,中括號內有引號。

♨點『.』就是“的”的意思。「物件.屬性」就是調用某個物件的某個屬性。
至於為什麼可以一直:物件.屬性.屬性....屬性...下去?因為屬性裡可以是另一個物件,那個物件裡還有屬性嘛,(因為物件、函數、陣列可以指定給一個物件的屬性),所以點『.』,就可以一直點下去...
就是指調用這個物件的哪個屬性中的哪個屬性(因為該物件中的某個屬性,存有另一個物件的參考嘛。而這個“另一個物件”也有屬性啊,所以就可以一直調用下去)。
2.用中括號存取也可以,倒是令人蠻意外的,而且中括號內的引號一定要加才行。感覺上物件跟陣列很像,而屬性則可以視為物件這個“陣列”的索引。



4.調用物件方法

物件.方法名稱(參數,參數,...,參數);

三.物件的類型

(1)自訂物件:就是使用者自訂的物件
(2)內建物件:就是JS內建的物件
(3)瀏覽器物件:IE或Netscape支援的物件,一般稱為BOM(Browser Object Model)
(4)ActiveX物件:上述三種物件之外的外部物件,即用C++或VB或Delphi所寫的一些外部物件。


四.一些和物件處理相關的東東


敘述語法說明備註
for-in敍述for(變數 in 物件){}運作很像for loop,可以用來調出一物件的所有屬性。♨參第四章其他和迴圈相關的東東
with敍述with(物件){}可以針對一個物件建立一程式區塊,在區塊中可以對物件的成員進行操作。(操作時不必指定物件名稱,物件為參數,可以說已預設指明是哪個物件了)
prototype物件物件(/類別).prototype.屬性名=屬性值;物件(/類別).prototype.方法名=函數名;物件.prototype=new 類別();所有的物件都有一個prototype屬性。不論物件是否巳實體化,我們都可以使用prototype屬性擴充任一內建或自訂物件的屬性和方法。♨參本章(第六章)第二節:物件-建立物件之新增物件屬性之prototype物件

1.注意,for-in的中括內没有引號,索引值嘛,没有引號反而正常點,否則就變字串了,使用for-in時中括號內加引號,還是會顯示屬性名稱(look有作用),但屬性值會顯示undefined。因為這樣就變成我們指定了一個名稱"look",JS按這個名稱去找會找不到.

2.但若是如上述存取屬性值,除了member.occupation(這個没問題),還可以用member["occupation"],反而這個可能就要注意了.此時中括號內寫的是屬性名就要加引號,否則就顯示不出來(完全没顯示)。
JS它設計就是這樣,誰也没辨法(很機車,變數還加什麼引號),類似的方法還有,如Object物件有個方法hasOwnProperty("屬性名"),也是要加引號.

3.for-in,若可以依序列舉可能會更清楚點,可以用:
var i=1;for(prop in c1){
document.write("屬性"+i+++":"+prop+"="+c1[prop]+"<br>");
}
因為只有一行,拆掉中括號變一行也行.
var i=1;for(prop in c1) document.write("屬性"+i+++":"+prop+"="+c1[prop]+"<br>");
♨例:
var prop;
var member=new Object;
member.name="索隆";
member.sex="男";
member.address="東海";
member.occupation="劍客";

for(look in member){//調閱物件member所有屬性名稱及屬性值
document.write("屬性:"+look+"="+member[look]+"<br/>");
}//prop會顯示所有屬性名稱,member[prop]會調出所有屬性值。

//顯示:
屬性:name=索隆
屬性:sex=男
屬性:address=東海
屬性:occupation=劍客

with(member){//對物件member進行操作
name="布魯克";
sex="男";
address="魔海";
occupation="音樂家、劍客";

document.write("姓名:"+name+"<br/>");
document.write("職稱:"+occupation+"<br/>");
}

//顯示:
屬性:姓名=布魯克
屬性:職稱=音樂家、劍客



第七章 陣列

一.聽說在JavaScript中,並沒有一個明確的陣列資料型態可供使用。
不過JS有內建陣列物件,或我們也可以自訂陣列物件來使用。
♨陣列物件,參第八章JavaScript的內建物件之陣列物件

1.定義一個array類別如下:

function MakeArray(n){
this.length="n";
for (var i=0;i<=n;i++){
this[i]=0
}
}

2.上已定義一個一維陣列類別,爾後只需要把物件生出來就行了,如:

sunny=new MakeArray(10);

則我們即有了個陣列物件,名為sunny,有11個元素,每個元素初始值為0。

3.要指定值時,再指明即可,如:

sunny[0]="魯夫";
sunny[1]="羅賓";
sunny[2]="香吉士";

二.使用內建的陣列物件

參:第八章 常見的JavaScript的內建物件之六:陣列物件


第八章 常見的JavaScript的內建物件

序號物件語法說明備註
1Arguments指向一個函數的參數.參數物件



一.參數物件(Arguments)
Arguments物件指向一個函數的參數.

1.只要一個函數被呼叫,就會自動建立一個Arguments物件,
每個函數都有一個區域變數arguments(因為每個Function物件都有一個arguments屬性),只要函數被呼叫,
函數中的區域變數arguments就會自動初始化並指向該Arguments物件,Arguments物件主要是提供一種方式,用來確定參數個數,並指向未命名的參數,因為呼叫函數時實際傳進來的參數數量,不見得是我們當初宣告時設定的參數個數.

2.在任一個函數裡,我們都可以使用關鍵字arguments,通常只在函數內使用.
arguments本質上是個區域變數,只在函數內使用,只要函數成立,arguments就會自動被宣告並初始化,用以指向函數的Arguments物件.
在行為上,arguments[]是個陣列(存放那麼多參數,不用陣列用什麼呢?),陣列的元素就是存放傳遞給函數的參數值.arguments[]陣列的元素個數就是傳進來的參數個數,arguments[]和其他陣列一樣擁有length屬性,可用以取得元素個數.
♨簡單地想就是說,有個物件它用來代表函數的參數,所以取名叫Arguments.
它裡頭定義了一個屬性用來存放函數的參數(到底是哪個屬性???是真的有個屬性還是怎樣?Function.arguments中不就巳經有存放函數的參數了???),而在任一個函數中我們都可以用非保留的關鍵字arguments指向Arguments物件.arguments[]的元素個數,就是傳入該函數的參數個數,arguments[]的元素就存放著傳進來的參數值


3.Arguments物件常見的屬性和方法
(a)Arguments物件,使得使我們可以調用(非保留的)關鍵字arguments來操作它,
除了可以用調動陣列元素存取參數值,和取得參數個數(length屬性)之外,還允許匿名函數可以指向自己(callee屬性),使函數能夠遞迴.

(b)從另一個角度來說,Arguments物件就像是具有callee屬性的陣列(除了有length屬性外,它還有一般陣列没有的callee屬性),不過Arguments物件終究不是Array類別的實體,一般陣列的length屬性可以讀寫,Arguments物件的length屬性是唯讀的,我們無法用它來改變陣列的長度.

(c)當函數具有巳命名的參數時,就造成了一個現象,
Arguments物件的陣列元素,是函數中存放參數值的一般區域變數的同義詞.
“參數名稱”或“Arguments物件”提供了指向同一個變數的兩種不同方式.
用參數名稱改變參數值,會改變用Arguments物件取得的值,反之亦然.若用Arguments物件改變了參數值,參數名稱也會取得被變更過的參數值.
♨Function物件也有個arguments屬性和length屬性
比較:Function物件


屬性內容
callee指向目前正在執行的函數
length傳遞給函數的參數個數

(1)callee
指目前正在執行的函數
a.用法,arguments.callee
b.例
//callee匿名函數使用callee指向自己,使函數能夠遞迴
var factorial=function(x){
if(x < 2) return 1;
else return x*arguments.callee(x-1);
//else return x*factorial(x-1);//用這行也是一樣的,匿名函數指定出去了,還是有名字能調動嘛
}


(2)length
指傳給函數的參數個數

這個length是Arguments.length,指實際傳給函數的參數個數,而不是宣告函數時設定的參數個數(預定的參數個),預定的參數個數是在Function.length中.

也就是說,Function.length指我們定義函數時宣告的參數個數.
但,因為Function.arguments是指傳遞給函數的參數(是個陣列)
所以真實傳進來的參數個數是Function.arguments.length(因為每個陣列物件必定有length屬性)

a.用法,arguments.length

b.例

//宣告一個函數checkArg,使用Arguments物件檢查是否傳遞正確的參數數目
function checkArg(args){
var actual=args.length;//實際傳進來的數目
var expected=args.callee.length;//預期的參數個數
if(actual!=expected){
throw new Error("不正確的輸入<br>我說要輸入"+expected+"個<br>你給我輸入"+actual+"個");
}
}

//調用checkArg()
function add(x,y,z){
checkArg(arguments);
return x+y+z;
}

//實際呼叫
//document.write(add(5,10,15,20,25));直接輸出是没有任何作用的,因為實際上有丟出了,但我們没有接

try{
document.write(add(5,10,15,20,25));
}catch(e){
if(e instanceof Error){
document.write(e.name+":"+e.message);
}
}

//顯示


♨呼叫add()時,傳入了5個數字,add()內部有收到了,它先把收到的參數(陣列)傳到checkArg()中,由區域變數args接收,args.length當然就是這個參數陣列的長度,這没問題嘛.
比較有的是args.callee,它是指向目前正在執行的函數,但没有指向checkArg(),卻是指向add(),args.callee.length就變成add.length了,就是3個.
所以,「arguments.callee:指目前正在執行的函數」,所謂「目前正在執行的函數」可能是用「呼叫時的函數」來判斷的.而不是“調用arguments時”的所在函數.
或說是arguments的所在位置的函數才對,因為調動arguments時,雖然用另一個變數args接收,但調用它,它會參考到arguments本來的位置(因為它是傳址嘛),而它本來的位置是在add()(因為它是add()的區域變數)



序號物件語法說明備註
1Global全域物件不必new。没有constructor屬性。
2Objectvar myObject=new Object();所有物件的祖先
3Function(後述)用以宣告函數或定義物件(宣告物件原型)
4Booleanvar myBoolean=new Boolean();可用以建立布林資料型態的物件
5Numbervar myNumber=new Number();可用以建立數值資料型態的物件
6Stringvar myString=new String();可用以建立和處理字串資料型態的物件
7Arrayvar myArray=new Array(數值);可用以建立陣列數值是指索引
8Datevar myDate=new Date();用以控制處理時間
8Math擁有和數學計算相關的屬性和方法不必new。没有constructor屬性。没有valueOf()方法
9Error可以取得執行時的錯誤資料,錯誤處理之用不必new。没有valueOf()方法
10RegExp「正規運算式」物件(Regular Expression)不必new

♨不能new的物件,無法使用prototype屬性和Expando屬性,所以没法任意擴充屬性。一般没有辨法new的物件都是直接用的

一.全域物件(Global)

全域物件是擁有全域屬性和全域函數的一個預先定義的物件.
(1).透過全域物件可以存取其他預先定義的物件及其屬性,但全域物件並不是任何物件的屬性,所以它没有名稱,一般會採用Global來描述它,只不過是為了方便並不是說全域物件名叫"Global".
(2).可以用"this"這個關鍵字以指向全域物件,但一般都不會用,也不必用,因為全域物件是JS作用範圍(scope chain)的頂端,所以在JS程式碼頂層所宣告的所有變數,其實都是Global的屬性,且所有不格的變數和函數名稱在調用時都會被JS作為該物件的屬性來查詢.而全域變數和全域函數都是全域物件的屬性.如調動eval()就是this.eval(),但其實直接調動就可以了,JS指向eval()程式碼,其實是指向全域物件eval的屬性.
(3).全域物件是一個物件没錯,是有這個東西,但它不是類別,没有建構式,無法實體化(不能new).
(4).實際上ECMAScript標準没有規定全域物件的型態,JS的實作或嵌入的JS都可以將任何型態物件都可以當作全域物件(隨便我們訂),只要該物件定義了下列基本屬性和方法.如在客戶端的JS裡,全域物件就是window.


2.全域物件常見的屬性及方法♨(比較)


常見的全域屬性
屬性說明備註
Infinity代表無窮大,載有Number.POSITIVE_INFINITY的初始值
NaN代表非數字值,載有Nnumber.NaN的初始值
undefined代表未定義的值




常見的全域方法
方法說明備註
isFinite(n)檢查某數值是否為無窮大
isNaN(n)檢查某數值是否為數字
parseInt("字串",數值)將字串開頭的數字轉換成整數參第一章第三節資料型態的轉換函數
parseFloat("字串")將字串開頭的數字轉成浮點數同上
eval("運算式")能把字串當作運算式,傳回一個運算式字串的運算結果同上
encodeURI("字串")對字串進行URI編碼
decodeURI("字串")對字串進行URI解碼
encodeURIComponent()對元件進行URI編碼1
decodeURIComponent()對元件進行URI解碼
escape("子串")將傳入的字串使用url編碼、傳回編碼後的字串註1
unescape("字串")將url編碼編碼後的字串、還原成編碼前的字串註1



(1)isFinite(n):若n是有限數字或可以轉成有限數字就會回傳true,若n不是數字(NaN)或是正負無窮大的數(Infinity,-Infinity)就會傳回flase.用來判斷某數值是否是用限的

(2)isNaN(n):若n是不是數字值就傳回true,否則傳回flase.
isNaN(n)用來判斷某數值是否是NaN,或一非法數值(如用0去除的結果)這個函數是必需的,因為NaN與任何值(包含它自己)比較得到的結果都是false,所以無法使用運算子==或===.要檢測一個數值是否為NaN,捨此函數別無它法.
通常用來檢驗parseFloat()和parseInt()的結果,判斷其是否為合法數字.(如用0為除數)
例:

傳回傳回
isNaN(0);falseisNaN(0/0);true
isNaN(parseInt("3"));falseisNaN(parseInt("hello"));true
isNaN("3");falseisNaN("hello")true
isNaN(true);falseisNaN(undefined);true


3.Global物件的屬性,要調用不必指名,就是直指打屬性名稱就可以(JS會自動指向全域物件中我們所調動全域屬性和方法)。
(1)全域物件預先定義的屬性無法明確地列舉,可以用for-in調出所有明確和不明確宣告的全域變數.
如:
var props=""
for(var prop in this)
props+=prop+"\n"
//document.write("屬性:"+prop+"="+this[prop]+"
");
因為this指向全域物件.
(2)全域物件的屬性還定義了JS所有預先定義的物件,如下列的Object,Function,Boolean,Number,String,Array等等.除了Math之外,其餘的都是定義類別的建構式,但Math指向的物件不是建構式.

二.Object物件
所有物件的先祖。是一個含有所有JS特點的超類別
Object類別是JS的內部資料型態,是JS所有物件的父類別.所以Object以外的所有JS物件都繼承Object屬性跟方法.

1.建構式
new Object()//建構式
new Object(n)//建構式
Object()//函數
var myObject=new Object();//實例

2.參數n,非必要參數,指定要物件型態是Number,Boolean或String,
new出一個Object物件時,參數若是數值,這個物件就是數值物件。參數若是布林,這個物件就是布林物件。參數若是字串,這個物件就是字串物件.
也可以作為函數使用,呼叫Object()其行為與new出來是一樣的.

3.回傳值,會傳回於參數中指定型態的物件,如布林物件,數字物件,字串物件,没有指定參數就單純傳回一個新建的物件,

4.Object物件常見的屬性方法♨這些東西大多滿機車的

屬性說明
constructor某物件的constructor屬性,指向該物件的建構式


方法說明
hasOwnProperty("字串")檢查物件的屬性是自己的,還是繼承而來的.
isPrototypeOf(物件)檢查某物件是否是指定物件的原型
propertyIsEmunerable("字串")檢查指定的屬性是否存在,以及能否用for-in列舉
toLocaleString()傳回件地區化的字串表示
toString()傳回物件的字串表示
valueOf()傳回物件的原始值(若存在的話)

(1)constructor
a.用法,object.constructor
b.某一物件的constructor屬性,指向該物件的建構式.如Array()建構式生出一個陣列物件array,則array.constructor指向Array.
var array =new Array();//生出一個物件
array.constructor==Array//結果是true.

constructor屬性常用來判斷一個未知物件的型態.假設有一未知值,則可以用運算子typeof判斷其是否是物件,若是物件的話,還可以進一步用constructor屬性判斷這個物件的型態.
function isArray(x){//用這個函數來判定一個給定的值是否是陣列.
return ((typeof x=="object")&&(x.constructor==Array))
}
♨這個函數只能用來判斷JS內建的物件,對於非JS內建物件就不見得適用了,object.toString()也能用來判斷一個未知物件的型態,但對於非JS內建物件也一樣不見得適用

(2)hasOwnProperty("字串")♨不熟
hasOwnProperty?照面義意:有自己的屬性嗎?
因為一個物件的屬性不見得是它自己的,除了有自己的,還有從原型物件中繼承下來的.
hasOwnProperty()用來判斷一個屬性是否是屬於自己的,還是繼承而來的.

a.用法,object.hasOwnProperty()
b.參數,作為參數的字串,指的是屬性的名稱
c.回傳值,若被點名的屬性(參數所指定的名稱的屬性),是繼承而來,或物件中根本無此屬性,則會傳回false.
hasOwnProperty()傳回true,表示這個屬性是該物件自己的.
但判斷方法也好像可以
d.例
function Circle(x,y){
this.w=0;
this.x=x;
this.y=y;
this.pi=3.14;
this.info=function(){
document.write("面積是:"+(this.x*this.x*this.pi)+"<br>");
document.write("圓周是:"+(this.y*this.pi)+"<br>");
}
}

Circle.prototype.z="圓舞曲";//在Circle添加一個屬性z
Circle.prototype.show= function() {//在Circle添加一個方法show
document.write("[半徑x是:" + this.x + ", 直徑y是:" + this.y + "]<p>");
}
----------------------
var c1=new Circle(5,10);//生出個圓實體叫c1
c1.info();//顯示面積是78.5,圓周長是31.400000000000002(調動方法ok)
c1.show();//顯示[半徑x是:5, 直徑y是:10](調動方法ok)
c1.add="good";//在c1增加一個屬性add

document.write("c1的w值是:"+c1.w+"<p>");//顯示0,c1有w屬性(取得屬性ok)
document.write("c1的x值是:"+c1.x+"<p>");//顯示5,c1有x屬性(取得屬性ok)
document.write("c1的pi值是:"+c1.pi+"<p>");//顯示3.14,c1有pi屬性(取得屬性ok)
document.write("c1的z值是:"+c1.z+"<p>");//顯示"圓舞曲",c1有z屬性(取得屬性ok)
document.write("c1的add值是:"+c1.add+"<p>");//顯示"good",c1有add屬性(取得屬性ok)
♨指名Circle調動屬性方法(如:Circle.w)不ok,屬性顯示undefined,方法會產生錯誤.類別無法調用嘛.JS會以為Circle是哪個物件,會先找看有没有Circle這個物件,再看看它有没有這個成員,但Circle這個物件不存在,所以找不到.
實際上用for-in調出所有c1的成員,包含在類別中定義的:w,x,y,pi,info,還有用prototype添加類別中的show,z,和在直接指定在c1中的add


document.write("w屬性:"+c1.hasOwnProperty("w")+"<br>");//傳回true,
document.write("x屬性:"+c1.hasOwnProperty("x")+"<br>");//傳回true,
document.write("d屬性:"+c1.hasOwnProperty("d")+"<br>")//傳回false,根本没這個屬性
document.write("info方法:"+c1.hasOwnProperty("info")+"<br>")//傳回true,
document.write("z屬性:"+c1.hasOwnProperty("z")+"<br>")//傳回false
document.write("測show方法:"+c1.hasOwnProperty("show")+"<br>")//傳回false,用prototype添加的
document.write("add屬性:"+c1.hasOwnProperty("add")+"<br>")//傳回true
document.write("測toString方法:"+c1.hasOwnProperty("toString")+"<br>")//傳回false,繼承來的

1.所以屬性跟方法都可以測,應該很合理,方法也是將函數塞進一個變數裡嘛.
2.該物件無指定的屬性,或該屬性是繼承而來,會傳回false.
如所有物件的祖先Object有toString,所以c1也應該會有,用if(c1.toString) document.write("yes");
判斷看看,答案是肯定的.但c1.hasOwnProperty("toString")會傳回false,
3.用prototype添加的成員,hasOwnProperty()也會回傳false.


(3)isPrototypeOf(物件)待查
照字面來看,可以看成是:是物件的原型嗎?
物件的原型是:經由建立並初始化該物件建構式而成立的.
這個方法用來判斷一個物件是否是另一個物件的原型.如
object.isPrototypeOf(o1),就是判斷物件object是不是o1的原型,這個可以用來判定物件的類別.

a.用法,object.isPrototypeOf(物件)
b.參數,一任意物件
c.回傳值,object.isPrototypeOf(o1),若object不是o1的原型,或o1根本不是物件,就會傳回false.
若object是o1的原型,就會傳回true.
d.例
var o=new Object();
document.write(Object.prototype.isPrototypeOf(o));//傳回true,o是物件
document.write(Function.prototype.isPrototypeOf(o.toString));//傳回true,toString是函數
document.write(Array.prototype.isPrototypeOf([1,2,3]));//傳回true,[1,2,3]是陣列
//延照上例:
document.write(Circle.prototype.isPrototypeOf(c1));//傳回true,
document.write(Circle.prototype.isPrototypeOf(cc));//無顯示,没這個物件(不會丟出例外嗎?)
document.write(Circle.prototype.isPrototypeOf(o));//傳回false,
♨網路看到的例子大多是這樣啦,但既是Object的方法,用Object.isPrototypeOf()不知行不行?
document.write(Object.prototype.isPrototypeOf(Function.prototype));//true,說明了函數的繼承

//句可以用上述的constructor屬性,達到同樣的效果,因為每個物件的constructor屬性都會指向該物件的建構式,所以
document.write(o.constructor==Object);//true,o的建構式是Object(由Object生出來的)
document.write(o.toString.constructor==Function);//true,o的toString是個函數

(4)propertyIsEmunerable("字串")
用來判斷一個物件的某個屬性是否是區域性的(不是繼承來的),和可否列舉(當然,前題是這個屬性要存在)
一般經由JS程式碼後天加入物件中的成員大約都可以列舉,內建物件預先定義的屬性没法列舉.而聽說ECMAScript標準規定propertyIsEmunerable()不能檢測“原型鏈”(原型範圍的東西),所以意味著這個方法只能適用於一個物件的區域屬性,繼承而來的屬性無法被檢測其是否能被列舉.
♨聽專家說這個方法没什麼用啦,當它被限制只能檢測非繼承屬性時,這個方法也就没什麼用處了.不過實際上,布魯克也覺得這個方法好像也真没什麼用處,有個簡單的邏輯,我要查一個屬性能不能被列舉,當然我要先知道有這個屬性存在才行啊.我要知道一個物件中有哪些屬性,當然我要先用for-in調出來看看啊,如果調出來的名單中没有某個屬性,我怎麼會知道“有它這個屬性的存在”???若我根本不知道這個屬性的存在,我要怎麼用propertyIsEmunerable()去輸入它的名字???
若一個屬性a,我知道有這個屬性存在,則for-in調出來没有屬性a,就表示它不能for-in調出來了啊,
若我根本不知道它的存在,而且for-in調出來的名單中也没有這個屬性,我怎麼會有辨法用propertyIsEmunerable()???我怎麼會想到要去看看屬性a是在幹嘛的?我根本就不知道有這件事啊.
難道我要閒閒没事從abcd,到按照字典一個字一個字測看看,有没有這個屬性?神經病,這個函數.

a.用法,object.propertyIsEmunerable("字串")
b.參數,是個字串,表屬性的名稱
c.回傳值,若我們指定的屬性名稱在某特定物件中是“繼承得來”,“不可列舉”或“不存在”,就會傳回false.若一個物件其具有我們指定屬性名稱的“非繼承”屬性,且這個屬性可以用for-in列舉,就會傳回true.
d.例
var o=new Object;
o.x=3.14;
o.propertyIsEmunerable("x")//true,屬性x是區域屬性,可列舉(當然前題是它存在)
o.propertyIsEmunerable("y")//false,根本没這個屬性
o.propertyIsEmunerable("toString")//false,繼承而來
Object.prototype.propertyIsEmunerable("toString")//false,雖不是繼承來的,但無法列舉

(5)toString()
這大概是用的最廣的方法.當我們有需要把物件轉成字串,就會用到它了,在很多地方我們没有調用toString()卻没有發生什麼大事.那是因為系統常常自動幫我們調用了.如
var msg="my object is a "+myObject;//系統會自動把myObject轉成字串.

當我們自定類別時,為類別量身打造一個toString()會很有用.很多物件如Boolean和Number等也都有自定自己專屬性toString(),若我們没有特別去定toString(),則調用的toString()就是Object類別預定的toString.跟Object.toString()是一樣的.傳回的字串形式如下:
[object class]
就是個物件類別,值可以是“Object”,“String”,“Number”,“Function”,“Window”,“Document”.....,這種行為有時對判別未知物件的型態或類別有用.♨要怎麼用?專家怎麼没講?由於很多物都有自定toString(),所以要調用的是哪一個,就要指清楚.

(6)valueOf()♨待查
一個物件的valueOf()會傳回與物件相關的基本值(若存在的話),如Object物件而言,由於其没有基本值,所以valueOf()傳回的是物件本身.Boolean物件就會傳回與該物件相關的布林值,String物件就會傳回與該物件相關的字串.

a.用法,object.valueOf()
b.回傳值,傳回跟object相關的基本值(若存在的話),若没有值與object相關,則會傳回物件本身.

♨搞不太清楚,這個方法到底要幹什麼???
用類別可以去調出來啦,會把一個類別的原始值秀出來,如function XXX(x,x){...}
如上面例字中的圓類別,用Circle.valueOf()調出來是長這樣:
function Circle(x,y){ this.w=0; this.x=x; this.y=y; this.pi=3.14; this.info=function(){ document.write("面積是:"+(this.x*this.x*this.pi)+"
"); document.write("圓周是:"+(this.y*this.pi)+"
"); } }
簡直就是把整張類別都秀出來(但用prototype添加的成員例外),若是物件去調動如c1.valueOf(),在IE下就會顯示:[object Object]
.


三.Function物件
function大概不是用來宣告函數就是用來定義物件的(宣告物件原型)
函數是JS的資料型態之一,Function可以用來建立一個Function物件(Function的建構式),不過一般是不會這樣做的,效率不高,

(1)function 函數名(參數,參數,...,參數){/*可能是函數或類別,
要看這裡有没有指定成員*/;}當然,可能連函數名也没有,就是匿名的函數。

(2)function 類別名(參數,參數,...,參數){
this.屬性名=屬性值;
....
this.方法名=函數;
...
}
//物件,定義完再new出來就行了。
var 變數(/實體物件名)=new 類別名(參數,...,參數)

(3)new Function("參數","參數",...,"敍述;");//Function建構式
♨參上述Function()建構式

var 變數=new Function("參數","參數",...,"敍述;");
//物件.等於是定義完直接new出來.

2.回傳值,新建的Function物件,或呼叫函數,即執行body中的敍述.
3.丟出,SyntaxError,參數或body中有語法錯誤就會丟出
4常見的屬性和方法

屬性內容
arguments[]
caller
length
prototype



方法內容
apply()
call()
toString()


(1)arguments(♨比較Arguments,參數物件)
傳遞給函數的參數,是個陣列

Function物件的arguments屬性是個參數陣列,其元素是傳遞給函數的參數,
只有在執行函數時,它才被定義.

a.用法,function.arguments[n]
function.arguments.length
♨EMCAScript v3巳將之廢除,看來不推荐使用

(2)caller
呼叫目前函數的函數

在JS早期的版本中,Function物件的caller屬性是呼叫目前函數的函數之參考指標,若該函數是從JS程式的頂層呼叫的,caller的值即為null.
caller屬性只能在函數內使用(只有在函數執行時會有定義)
♨未例入EMCAScript 標準

a.用法,function.caller

(3)length
巳宣告的參數個數

length屬性指向我們定義函數時宣告的參數個數(設定時預設的參數個數),不是實際呼叫時傳遞出去的參數,實際呼叫時傳遞給它的參數個數可以比它多也可能比它少.

a.用法,function.length

(4)prototype
物件類別的原型

prototype屬性在函數當作建構式時使用.它指向整個物件類別的原型物件.
由此建構式建立的任何物件都會繼承prototype屬性指向的物件之所有屬性.

a.用法,function.prototype

(5)apply(this物件,陣列)(待查)
a.用法,function.apply(this物件,陣列)
b.參數,第一個參數是呼叫function的物件,在函數主體中,是關鍵字this的值
第二個參數是陣列或陣列物件(Arguments物件)
c.回傳值,呼叫函數function的回傳值
d.丟出,TypeError,若呼叫該函數的物件不是個函數,或第二個參數不是陣列或Arguments物件,就會丟出.
e.例

(6)call()(待查)
將函數當作物件的方法呼叫
a.用法,function.call(this物件,x)
b.參數,第一個參數是呼叫function的物件,在函數主體中,是關鍵字this的值
第二個參數以降是:“任意多個參數”,這些參數將傳遞給函數function.
c.回傳值,呼叫函數function的回傳值.
d.丟出,TypeError,若呼叫該函數的物件不是個函數,或第二個參數不是陣列或Arguments物件,就會丟出.
e.例

(7)toString()
把函數轉換成字串
聽說會將含有JS的程式碼的有效字串傳回,即關鍵字function,參數,和函數的完整主體.
♨那不是跟object.valueOf()一樣嗎?
a.用法,function.toString()
b.回傳值,表示函數的字串
c.丟出,TypeError,若呼叫該函數的物件不是Function,就會丟出例外


四.Boolean物件
在JS中,布林值是基本資料型態的一種,Boolean是將布林值包裏起來的一種物件(將布林值物件化).
主要是因為提供了toString(),可以將布林值傳換成字串.

1.建構式
new Boolean(n)//建構式
Boolean(n)//轉換函數
var myBoolean=new Boolean(true);//實例

2.參數n,是Boolean物件要存放的值,或要轉換成布林值的值.
參數傳入的,若是「false」、「0」、「null」、「空字串」、「NaN」、「undefined」:布林值皆為false,其餘皆為trun(含"false"字串)。

3.回傳值
用建構式形式呼叫(用new運算子)時,Boolean()會將我們傳入的參數轉換成布林值,且傳回包含該值的Boolean物件
若以函數的形式(不用new)呼叫時,Boolean()只會將它的參數轉換成布林值傳回來.

4.Boolean常見的屬性方法

constructor(待查)
prototype對物件添加屬性和方法


toString()根據Boolean物件所指向的布林值傳回true或false字串
valueOf()傳回Boolean物件中所指向的布林值(傳回在存放Boolean物件中的原始值)


(1)toString()//根據Boolean物件b的值傳回字串"true"或"false"
var b=new Boolean();
b.toString();

(2).valueOf()//傳回在存放Boolean物件中的布林值

若呼叫toString(),valueOf()時,調動本方法的物件不是Boolean型態,會丟出例外(TypeError)

五.Number物件
將數字包裏起來的物件(將數字物件化)
通常用Number物件是為了使用toString()方法,將數值轉成字串。
1.建構式
new Number(n)//建構式
Number(n)//函數
var myNumber=new Number(n);//實例

2.參數n&回傳值,n是要建立Number物件的數值或要轉換成數字的值.
也可以不new,用Number(n)作為函數呼叫,則Number(n)會把自己的參數n轉成基本的數值傳回來(若轉換失敗會傳回NaN).若new出來,它傳回的是新建立的Number物件.



2.Number物件常見屬性跟方法

常數說明
NaN一個用來表示非數字的特殊值
MAX_VALUEJS能表達的最大值,傳回JS數值中的最大值
MIN_VALUEJS能表達的最小值,傳回JS數值中最接近0的值
POSITIVE_INFINITY正無窮大,傳回比Number.MAX_VALUE更大的正值
NEGATIVE_INFINITY負無窮大,傳回比Number.MIN_VALUE更大的負值

♨參考第一章資料型態之JavaScript的一些特別數值

方法說明
toString(n)依指定進位(n)將數字轉換成字串
toLocaleString()依當地數字格式,將數字轉換成字串
toPrecision()依指定的位數(n),將數字轉換成字串
toFixed(n)將數字四捨五入為指定小數位數的數字,並以字串傳回
toExponential(n)將數字採指數表示法表示,並以字串傳回
valueOf傳回數字物字的原始值

(1)Number有5個表示最大,最小,正無窮,負無窮,非數值等數字常數(都是是常數喔),這些屬性都是Number建構式本身的屬性,但不是副本本身的屬性(奇怪?怎麼會這樣?待查)
如:
var biggest=Number.MAX.VALUE;//合法
var n=newNumber(2);
var biggest=n.MAX.VALUE;//這樣不行
有指定參數想來也是不行,没參數也不行嗎?待查

(2)toString(n),可以將數字(物件)(依指定的進位)轉換成字串,並傳回结果。
a.用法,number.toString(n)
b.參數n,非必要參數,是個2~36之間的數字,表示數字的基數(就是進位啦).若省略參數n,則會以基數10傳回(以十進位傳回),
c.回傳值,傳回某數字型態的字串
d.錯誤,TypeError:呼叫本方法的物件,若不是Number會丟出例外TypeError.
e.例
var n=new Number(12345.6789);
//var n=12345.6789;//或直接寫這樣(參考用法a)

n.toString()//傳回12345.6789(没有指定參數,預設以10進位傳回)
//n.toString(0)//0超出範圍(2~36)(奇怪,不會丟出RangeError例外嗎?待查)
//n.toString(1)//1超出範圍(2~36)
n.toString(2)//傳回11000000111001.101011011100110001100011111100010100001
n.toString(5)//傳回343340.314412401240124020(5進位)
n.toString(10)//傳回12345.6789(10進位)

(333.123).toString()//傳回333.123//或直接寫這樣(參考用法a)
(333.123).toString(2)//傳回101001101.00011111011111001110110110010001011010000111
(333.123).toString(5)//傳回2313.03014141414141414140
(333.123).toString(10)//傳回333.123

(3)toLocaleString(),將數字(物件)轉換成當地格式的字串,並傳回结果。
a.用法,number.toLocaleString()
b.回傳值,據當地規範格式化數字,並傳回字串,(可能影響到小數點或千分位分隔符號)
c.錯誤,TypeError,呼叫本方法的物件,若不是Number會丟出例外TypeError.

(4)toPrecision(n),將數字(物件)依指定的位數(n)轉換成字串,並傳回结果。
a.用法:number.toPrecision(n)
b.參數,為1~21之間的數字(有的實作可能支援更大或更小的範圍),表示傳回字串的有效位數,若省略參數n,就會調動toString,(效果與toString一樣).
c.回傳值,傳回(以參數n指定的)n位數的數字型態字串,若n夠大足夠包括數字整數部分的所有數字,則傳回的字串會採用固定小數位數表示法,否則採用指數表示法,即小數點前有一位數字,小數點後有n-1位數,太長的數字會被四捨五入,太短的數字會補0,以達到我們指定的長度.
d.錯誤,
(a)RangeError:參數n太小或太大時(超出1~21)會丟出例外RangeError.(有的實作可能支援更大或更小的範圍)
(b)TypeError:呼叫本方法的物件,若不是Number會丟出例外TypeError.
e.例
var n=new Number(12345.6789);
//var n=12345.6789;//或直接寫這樣(參考用法a)

n.toPrecision();//傳回12345.6789,直接調用toString()
//n.toPrecision(0);//超出範圍(1~21),會產生錯誤
n.toPrecision(1);//傳回1e+4
n.toPrecision(5);//傳回12346(有效位數5位,四捨五入的結果)
n.toPrecision(10);//傳回12345.67890(有效位數10位,補1個0以達到第10位數)
(333.123).toPrecision();//傳回333.123
//(333.123).toPrecision(0);//超出範圍(1~21),會產生錯誤
(333.123).toPrecision(1);//傳回3e+2
(333.123).toPrecision(5);//傳回333.12

(5)toFixed(n),用固定小數位數表示法格式化數字,以字串型態傳回
a.用法,number.toFixed(n)
b.參數n,為0~20間的數字(有的實作可能支援更大或更小的範圍),表示小數點後的位數,若省略參數n,JS會以0代替.
c.回傳值,會傳回(以參數n指定的)固定小數位數的數字型態字串,即傳回小數點後有n位數的數字,太長的數字會被四捨五入,太短的數字會補0,以達到我們指定的長度.
(如果數值大于 le+21,則此方法只會呼叫 Number.toString(),傳回用指數表示法表示的字符)據參數n指定的長度,小數點前有一位,小數點後有n位.
d.錯誤,
(a)RangeError,參數n太小或太大時(超出0~20)會丟出例外RangeError.(有的實作可能支援更大或更小的範圍)
(b)TypeError,呼叫本方法的物件,若不是Number會丟出例外TypeError.
e.例
var n=new Number(12345.6789);
//var n=12345.6789;//或直接寫這樣(參考用法a)

n.toFixed();//傳回12346(四捨五入的結果)
n.toFixed(0);//傳回12346
n.toFixed(1);//傳回12345.7(小數點後1位,四捨五入)
n.toFixed(5);//傳回12345.67890(小數點後5位,補1個0以達到小數點第5位)
n.toFixed(10);//傳回12345.6789000000(小數點後10位,補6個0以達到小數點第10位)

(333.123).toFixed();傳回333//或直接寫這樣(參考用法a)
(333.123).toFixed(0);傳回333
(333.123).toFixed(1);傳回333.1
(333.123).toFixed(5);傳回333.12300
(1.2e+10).toFixed(2)//傳回12000000000.00(待查?)
(1.2e-10).toFixed(2)//傳回0.00

(6)toExponential(n):用指數表示法格式化數字,以字串型態傳回.
a.用法:number.toExponential(n)
b.參數n,為0~20之間的數字(有的實作可能支援更大或更小的範圍),表示要傳回以指數表達的字串結果,表現到小數點第幾位.若省略參數n,JS將盡可能使用所能支援的最大位數.
c.回傳值,會傳回以指數表現的數字型態字串,據參數n指定的長度,小數點前有一位,小數點後有n位.
d.錯誤,
(a)RangeError:參數n太小或太大時(超出0~20)會丟出例外RangeError.(有的實作可能支援更大或更小的範圍)
(b)TypeError:呼叫本方法的物件,若不是Number會丟出例外TypeError.
e.例
var n=new Number(12345.6789);
//var n=12345.6789;//或直接寫這樣(參考用法a)

n.toExponential();//傳回1.23456789e+4
n.toExponential(0);//傳回1e+4
n.toExponential(1);//傳回1.2e+4
n.toExponential(5);//傳回1.23457e+4
n.toExponential(10);//傳回1.2345678900e+4

(7)valueOf()
a.用法,number.valueOf();
b.回傳值,傳回數字物件的原始值
c,錯誤,呼叫本方法的物件若非數字物件,會丟出例外TypeError.

六.String物件

字串物件內載了不少方法用以操作字串。

字串(string)或是在此之前的數值(number)、布林(boolean)等等,其實都是JS的基本資料型態。
以字串來說,字串是JS的基本資料型態。但也可視為物件(前已述及JS裡所有的東西都是物件)。
正確地說,字串是JS基本資料型態之一,而String類別提供了大量操作字串數值的方法.
與Number,Boolean一樣,String物件將字串的資料值包裏起來成為一個物件.如此我們即可調用String類別中定義的方法,以操作字串.所以這個物件其實很有用,滿重要的吧,看其他的物件大都提供toString()就知道了.♨實際上,String物件提供的方法,無法改變字串原本的內容,如toLowerCase()會將字串轉換成小寫,但它傳回的是一個轉換成小寫後的全新字串,並不是去修改原先的字串再傳回來.JS的字串是不變的(immutable)

1.建構式
new String("字串")//建構式
String("字串");//轉換函數
var str="布魯克";//實例,指定值
var objStr=new String("布魯克");//實例,生出物件

2.參數,要儲存在String物件中的值或要轉換成基本字串的值.

不管是直接指定字串,或是new出一個字串物件,實際上字串變數str,和字串物件objStr都是一種...字串物件(String物件)(...有點繞口令)。不論是用何種方式建立的字串,都可以使用JS內建的字串物件方法,對字串進行操作。唯一的差別是,直接指定而來的"物件",因為不是new出來的,不能用prototype屬性和Expando屬性,字串物件可以,且字串物件是可以擴充成員的。)

♨但差別在哪裡呢?布魯克也不知道。如果都没差別...好像有點矛盾,因為基本資料型態是傳值嘛,物件是參考型態是傳址嘛。如果都没差別:「var objStr=new String("布魯克");」到底是傳值還是傳址呢???,布魯克也不知道...呵呵。連要怎麼傳出去,傳出去要怎麼收也不知道,就算收到,收到了要怎麼調用也不知道。因為一般而言,資料值都是塞給屬性的嘛,要操作物件的對象也都是物件的成員,這三個物件的屬性是?...什麼?...不知道。
曾試著用for-in敍述去調,嗯...調不出來。
直接輸出是可以看到,這倒是怪事。一般有成員的物件,如:「var man=new Object();
man.name="布魯克";」用for-in可以調出來,這没問題嘛,但若直接輸出物件如「document.write(man);」就會顯示:「[object Object]」表示這是一個物件(object),物件的類型是“物件(Object)”。
但若直接輸出字串物件如「document.write(objStr);」,反而顯示「布魯克」了???數值物件和布林物件也是一樣的情形。
在宣告時是new出一個物件,所以傳出去的應該也是物件吧,接收的函數收到的也應該是物件啊。但因為顯示出來的結果,它裡頭記載的是值,所以布魯克試著指定別的值給它,看看會怎麼樣。測試的結果在這裡。結果它的傳送效果和傳值是一樣的,感覺就像一般記載基本資料型態的變數一樣,並没有動到正本。


3.回傳值,當String()作為建構式時,會傳回新建立的String物件,裡頭存放的是參數傳入的字串或傳入參數的字串表示,或呼叫String()函數,則會將傳入的參數換換成基本的字串資料型態並傳回.


4.字串物件常見的屬性和方法

屬性說明
length取得字串長度(字串物件的這個屬性裡儲存的是字串的字元數)



方法作用備註
indexOf("字串",n)傳回第一次搜尋到該字串的索引位置,若没有找到該字串會傳回-1。字串指要搜尋的字串,數值為開始搜尋時的索引位置取得位置
lastIndexOf("字串",n)從尾部開始搜尋,傳回第一次搜尋到字串的索引位置取得位置
charAt(n)取得參數在數值位置的字元,數值指索引值,索引值從0開始。(在某字串中,取得在某指定位置的字)取得字元
charCodeAt(n)取得參數在數值位置的unicode字碼,數值指索引值。(在某字串中,取得在某指定位置字的unicode編碼)取得字元碼
substring("數值1","數值2")取出從數值1到數值2之間的子字串。數值1和數值2都是指索引取得字串
substr("數值1","數值2")從數值1的位置開始取出數值2所指定的字元數。數值1是指索引,數值2是長度取得字串
slice(n,n)擷取出指定的字串片段並傳回取得字串
split("字串")使用字串作為要分割的依據分割,傳回一個陣列物件分割
concat("字串")將該字串新增到String物件的字串後,可結合兩個字串結合
toLowerCase()將字串的英文字母轉小寫轉小寫
toUpperCase()將字串的英文字母轉大寫轉大寫
search("regexp")傳回第一次搜尋到該字串的索引位置,若没有找到該字串會傳回-1取得位置
match("regexp")傳回第一次搜尋到該字串的(字串)值,搜不到會傳回null取得字串
replace(regexp|"字串1","字串2")搜尋到字串1時替換成字串2替換
toString()傳回string的基本字串值調動者非String,丟出TypeError
valueOf()傳回string字串的原始字串值調動者非String,丟出TypeError



4.1.以下方法可將String物件的字串內容輸出成相對應的html標籤編排方式。

方法說明
anchor()傳回<a>string</a>
big()傳回<big>string</big>
blink()傳回<blink>string</blink>
bold()傳回<b>string</b>
fixed()傳回<tt>string</tt>
fontcolor(#rbg)傳回<font color="#rbg">string</font>
fontsize(數值)傳回<font size="數值">string</font>
italics()傳回<i>string</i>
link(url)傳回<a href="url">string</a>
small()傳回<small>string</small>
strike()傳回<strike>string</strike>
sub()傳回<sub>string</sub>
sup()傳回<sup>string</sup>


4.2.String物件還提供了靜態方法

方法說明
fromCharCode(n,n,...,n)把傳入的字串參數字元編碼建立新字串


(1)length
String物件的length屬性,代表字串的字元數

string.length如用法所示,不一定非要字串物件String,任何一個字串string都可以呼叫.(因為在JS中的任何東西都是物件嘛,就這樣想好啦)
字元的索引都是由0開始跳,所對於任一個字串str,其最後一個字元的索引值都是str.length-1.
length屬性是唯讀的,用for-in敍述無法列舉,用delete無法刪除.

a.用法,string.length
b.例
var str=new String("夜明歌‧直貫刺");
var str1="前奏曲‧破兵";
var str2="革命舞曲‧穿心";
var str3="酒桶舞曲‧疾雨";
document.write(str.length+"<br>");//傳回
document.write(str1.length+"<br>");//傳回
str.length的值應該是7,開任何個網頁測試都會顯示7,只有七個字嘛。至於為何在blogger開出來是13?str1.length長度只有6,開出來是12,真是見鬼.
「‧」這個字元的Unicode編碼是8231啦,只有一個,但後面布魯克用charCodeAt()調出來過,它在blogger上會被解析成「38,35,56,50,51,49,59」,變7個,這個blogger真是很有趣的.


(2)fromCharCode(n,n,...)
用指定的字元編碼建立新字串

注意用法,這是個靜態方法,是用類別調動的.並不是String實體的方法,當然也不是任何一個字串可以調動的.
行為跟charCodeAt()相反,charCodeAt()可以在某字串中取得某字元的編碼,fromCharCode()是由字元碼去建立字串.

a.用法,String.fromCharCode(n,n,...)
b.參數,n是個數值(整數),表要建立的字串中的某個字元碼
c.回傳值,傳回含有指定字元編碼的新字串
d,例
var reStr=String.fromCharCode(22812,26126,27468,8231,30452,36011,21050);
document.write(reStr);//傳回:
♨當然,22812等Unicode編碼,是由charCodeAt()得到的,
另外,在JS1.2,並没有完全支援fromCharCode()


(3)indexOf("字串",n)
搜索字串
indexOf("字串")按字面的意思,就是:字串的索引嘛.
string.indexOf("字串"),能在string字串裡搜索,尋找指定在參數的字串,並傳回字串在string字串中的索引值.

a.用法,
string.indexOf("字串")
string.indexOf("字串",n)
b.參數,第一個字串參數表示要在字串string中搜索的子字串.第二個參數n,非必要參數,是個整數的索引值,由0開始跳(預設值,表第一個字元),是字串string的位置,表示要在字串string中的第n個位置(第n+1個字元)開始搜尋子字串.
c.回傳值,在string字串中從我們指定的位置n開始搜索我們指定的子字串,如果找到我們在第一個參數中設定的子字串,就傳回子字串的第一個字元在string字串中的位置(索引值),若在搜索的範圍中没有找到,就傳回-1.

d.例
var str="革命舞曲‧穿心";
document.write(str.length+"<br>");//傳回7(共7個字,但索引值由0開始跳,所以最大到6,0~6)
document.write(str.indexOf("穿",2)+"<br>");//傳回5(第5個位置,表第6個字)
document.write(str.indexOf("劍",2)+"<br>");//傳回-1(没有這個字)
document.write(str.indexOf("穿",8)+"<br>");//傳回-1(指定的位置超出範圍)
document.write(str.indexOf("穿",6)+"<br>");//傳回-1(指定的子字串位置在指定要搜索位的置之前,自然搜不到)
♨在JS1和1.1中,若指定的位置n超出string字串的長度,回傳回空字串,而不是-1.另外呢,在blogger中,上述在某些符號的字元碼它會解析成不同字元碼的情況,還是存在,像"革命舞曲‧穿心",它會解成13個字,這個問題也不曉得是怎麼回事,若没有解決,可能很多事不能做


(4)lastIndexOf("字串")
從尾部開始搜尋,傳回第一次搜尋到字串的索引位置
indexOf()的兄第,indexOf()從頭開始正向地搜,lastIndexOf()從尾部開始反向搜.
a.用法,
string.lastIndexOf("字串")
string.lastIndexOf("字串",n)
b.參數,第一個字串參數表示要在字串string中搜索的子字串.第二個參數n,非必要整數參數,是索引值,由0開始跳(預設值,表第一個字元),表示字串string的位置,即在字串string中的第n個位置(第n+1個字元)開始反向搜尋子字串.
c.回傳值,在string字串中從我們指定的位置n開始反向搜索我們指定的子字串,如果找到我們在第一個參數中設定的子字串,就傳回子字串的第一個字元在string字串中的位置(索引值),若在搜索的範圍中没有找到,就傳回-1.省略第二個參數n,就會從尾部開始搜.
註:只有搜索的動作是反向搜,指定位置的索引值,和找到字串後,傳回的索引值仍是由頭部開始計數.

d.例
var str="革命舞曲‧穿心";
document.write(str.length+"<br<");//傳回7(索引值由0~6)
document.write(str.lastIndexOf("穿",2)+"<br>");//傳回-1(由第三個字開始反向搜尋,查無此字)
document.write(str.lastIndexOf("劍",2)+"<br>");//傳回-1(没有這個字)
document.write(str.lastIndexOf("穿",8)+"<br>");//傳回5(指定的索引值超過字串的長度範圍,仍不受影響)
document.write(str.lastIndexOf("穿",6)+"<br>");//傳回5(第6個字)

(5)charAt(n)
在某字串中,取得在某指定位置的字

a.用法,string.charAt(n)
b.參數,數字n是索引,表示指定字串中要取得的第n個字元,0≤n≤string.length-1
c.回傳值,傳回string字串中的第n個字元,若指定n超出範圍,會傳回一個空字串,其長度是1
d.例
var str1="前奏曲‧破兵";
for(var i=str1.length-1;i>=0;i--){//反向擷取字元
document.write(str1.charAt(i));
}//顯示:
♨若字串是:前奏曲‧破兵中的,因「‧」這個字元碼是&#8231,若倒取,就會出現1328#&變成:兵破1328#&曲奏前

(6)charCodeAt(n)
在某字串中,取得在某指定位置的字元編碼
charAt()的兄弟,charAt()傳回字元,charCodeAt()傳回字元的編碼.

a.用法,string.charCodeAt(n)
b.參數,數字n是索引,表示指定字串中要取得的第n個字元的編碼,0≤n≤string.length-1
c.回傳值,傳回字串中指定字元的字元編碼,傳回的值是第n個字元的Unicode編碼,其值於0~65535之間的16位元整數,若指定n超出範圍(負數或大於等於字串長度),會傳回NaN.
d.例
var str=new String("夜明歌‧直貫刺");
var str1="前奏曲‧破兵";
for(var i=0;i < str.length;i++){
document.write(str.charCodeAt(i)+",");
}//顯示:
for(var i=0;i < str1.length;i++){//任一個字串都可以呼叫,
document.write(str1.charCodeAt(i)+",");
}顯示:
♨這個blogger,真是敗給它啦,正常的話「夜明歌‧直貫刺」應該是顯示:「22812,26126,27468,8231,30452,36011,21050」,「‧」這個字元的Unicode編碼是8231,奇怪,隨便開個網頁測試都是這個結果(不信你開看看),就是在blogger不一樣...呵呵呵,且若用charAt()倒取,遇到「‧」這個符號就會變成1328#&。顯然,「‧」這個字元的Unicode編碼就是8231,是可以肯定的。只有七個字啊,為何「‧」這個字元的Unicode編碼會變成「38,35,56,50,51,49,59」???呵呵呵,我也不知道,這個blogger,真是太神奇啦.調用String.fromCharCode(8231)用字元碼去重建文字,會傳回「‧」這個符號,但用charCodeAt(‧)去取得「‧」這個符號的字元碼,會變成「38,35,56,50,51,49,59」

(7)substring(n1,n2)
擷取子字串,從n1指定的位置開始取,取到指定位置n2的所有字元.
a.用法,string.substring(n1,n2)
b.參數,整數參數n1,是個索引值,表示要開始擷取子字串的位置,
整數參數n2,是個非必要參數,為索引值,代表要擷取的子字串結束的位置,若省略,會將string字串從指定n1的索引位置開始取到string字結束.
n1跟n2就是用來指定位置而巳啦,但若設定n2,它的設計是,取到n2的前一個位置(就是不含n2所在位置的字元)
c.回傳值,
d.例
var str1="前奏曲‧破兵";

♨1.實際測試的結果,第一個參數,指定負數效果跟設為0是一樣的.
2.測試結果,指定長度(第二個參數)超出字串string的範圍,一樣會取到字串完畢,
若n1=n2,會傳空字串(當然了,n=n從n取到n,裡面就没字啊)
若設0,此時n1若為0(0,0)變成n1=n2,就傳回空字串,若此時n1為負數,等同是0,(-n,0)等同於(0,0),n1=n2也傳回空字串.
總之(0,0)(-,0),(0,-),(-,-)都是傳回空字串.
3.若是(+,0),從第一個正整數參數位置的前一個字元開始,反向傳回n1之前的字串.
另外,奇怪了?這個函數跟slice(n1,n2)有什麼不一樣呢?


(8)substr(n1,n2)
擷取子字串,從n1指定的位置開始取出指定n2長度的字元.
a.用法,string.substr(n1,n2)
b.參數,整數參數n1,是個索引值,表示要開始擷取子字串的位置,索引值可以為負,表示從尾部開始算,-1指string字串的最後一個字元,-2指string字串的最後一個字元.(聽說是這樣,但實際測試的結果,n1指定負數就視作0.)
整數參數n2,是個非必要參數,代表要擷取的子字串長度,若省略,會將string字串從指定n1的索引位置開始取到string字結束.
c.回傳值,從n1指定的位置開始,取出n2長度的所有字元.
d.例
var str1="前奏曲‧破兵";


♨1.實際測試的結果,第一個參數,指定負數效果跟設為0是一樣的.
2.指定長度(第二個參數)超出字串string的範圍,一樣會取到字串完畢,若設0,不論n1為何都會傳回空字串(滿合理的吧,不管位置在哪裡,取0個字,既然没半個,不傳回空字串要傳什麼?),還有n2是長度,長度是没有人設負的吧.
另外聽說ECMAScript並没有這個方法標準化,看來並不推薦使用(奇怪,滿好用的啊,呵呵)


(9)slice(n1,n2)
依指定的位置擷取出一個字串片段

a.用法,string.slice(n1,n2)
b.參數,第一個整數參數n1,是個索引值,表示要開始擷取的位置.第二個整數參數n2表示結束的位置,是個非必要參數,若省略,就會從指定n1的位置開始取到字串完畢.
n1跟n2就是用來指定位置而巳啦,但若設定n2,它的設計是,取到n2的前一個位置(就是不含n2所在位置的字元)
也可以指定負數啦,表示要從字串尾部開始算起的意思,方便要從後面算過來的倩況,-1就是最後一個字元,-2就是倒數第二個字元,

c.回傳值,傳回從n1開始(包含n1)到n2結束(不含n2)的所有字元

n1012345
stringabcdef
n2-6-5-4-3-2-1

d.例,
var str3="酒桶舞曲‧疾雨";



(10)split("字串",n)
將字串分割成字串陣列

a.用法,string.split("字串",n)
b.參數,第一個參數是個字串或正規運算式
c.回傳值,


方法中如:myArray=str1.split('str2');。str2是切割的特徵,str1是要切割的字串(待切割的),myArray是切割的結果。儲存時「var myArray1=str1.split('str2');」或
「var myArray2=new Array();
myArray2=str1.split('str2');」
是一樣的。調用時myArray1[0]或myArray2[0]等,或用loop全部調出,不過直接write也能write出陣列所有元素,如:「document.write("split('str2')切割結果:"+str1.split('str2');」或「document.write("split('str2')切割結果:"+myArray1;」或直接write出myArray1結果也是一樣的。
(更多陣列特性,參陣列物件)

(11)concat("字串")
連接字串
可將指定的字串參數加在一個字串(物件)上
a.用法,string.concat("字串","字串",...)
b.參數,字串參數是要加到字串string後方的字串
c,回傳值,會將每個連接到字串string上的新字串傳回
string.concat()如用法所示不一定非要字串物件String,任何一個字串string都可以呼叫.
它的行為跟使用加號「+」連接字串是一樣的.Array.concat也是類似的函數.
如:
str3=str1.concat(str2);//str1連接str2
作用相當於str3=str1+str2。//除非有特別需要,否則一般都會用「+」比較快.

(12)search(regexp)
a.用法,string.search(regexp)
b.參數,Regexp,
c.回傳值,字串string中第一個與regexp相符子字串的開始位置.
若没有找到相符的字字串,則傳回-1.

search()這個方法,不會執行全域比對,它會忽略修飾子g,和regexp的lastIndex屬性,
就是說它是從字串string的開頭開始搜尋,總是傳回string第一個相符位置

d.例
var text="“酒桶舞曲‧疾雨”";


(13)match(regexp)(比對)
找出regexp指定的字串

a.用法,string.match(regexp)
b.參數,RegExp物件
(似乎是直接寫RegExp就行了,若不是RegExp物件,JS會自動將之傳給RegExp()建構式,轉成RegExp物件)
c.回傳值,match()會搜尋字串string,找出一個或多個與參數中的regexp相符的文字,並將比對結果傳回存放在陣列中.若搜尋不到字串就傳回null.
(c1)若RegExp没有使用修飾子g,則match()就只會在string中執行一次比對,
該陣例的第0個元素存放的是在字串中比對後相符的文字,其餘的元素存放的是正規運算式的子運算式相符的文字,該陣列還含有兩個物件屬性:index屬性指出相符文字的起始字元在string中的位置,input屬性指定string的參考指標.
(c2)若RegExp有使用修飾子g,則match()就會找出string中所有相符的字串,陣例元素存放的是string中所有相符的字串,並且這個陣例没有index和input屬性.
也就是說,若RegExp有使用g修飾子natch()不會提供與子運算式相符文字的資訊,也不提供每個相符子字串的位置,若要知道這全域比對旳資訊,要使用RegExp.exec().
d.例
var see="1 plus 2 eqals 3".match(/\w+/g);
♨若不設定全域比對,搜到1就會停止
var url=/(\w+):\/\/(\S+)\/(\S*)/;
var text="Vist my home page at http://beba-brook.blogspot.com/";
var result=text.match(url);
if(result!=null){
var fullurl=result[0];
var protocol=result[1];
var host=result[2];
var path=result[3];
}


(14)replace(regexp|"字串","字串")(替換)
取代與regexp相符的子字串
a.用法,string.replace(regexp,"字串")
b.參數,第一個參數,regexp物件或字串,表示指定要被取代的樣式,字串.第二個參數是個字串,表示要替換的文字.(聽說ECMAScript v3以後,第二個參數也可以是個函數)
c.回傳值,將string字串中regexp所指定的樣式,由指定的字串取代並傳回.
但第二個參數有個特殊的用法,見下表

$1,$2,$3...$98,$99等同regexp中第1個到第99個加括號的子運算式相符文字
$&與regexp相符的子字串
$'位於相符子字串左側的文字
$'位於相符子字串右側的文字
$$實字$符號


d.例
var text="“酒桶舞曲‧疾雨”";
var text2="binks’sake";
//將雙引號的“”形態改成「」形態
var text3=text.replace(/“([^”]*)”/g,"「$1」");
//將賓克斯的酒位置對調
var text4=text2.replace(/(\w+)\s*’\s*(\w+)/,"$2’$1");
//將字串中的每個字開頭改大寫
var text5=text2.replace(/\b\w+\b/g,function(word){
return word.substring(0,1).toUpperCase()+
word.substring(1);
}
);

♨text3没有將雙引號“”形態改成「」是這個符號「‧」的關係,拿掉是可以正常替換掉的.在其他的網頁也都可以
上面是換個符號的結果,用「-」在blogger就没問題,否則就只好分兩段作

var text="“酒桶舞曲‧疾雨”";
var text2=text.replace("”","」");
var text3=text2.replace("“","「");



(15)localeCompare("字串")♨待查
用當地特定的順序來比較兩個字串
若以比較運算子<或>比較字串,則是以字元的Unicode編碼為基礎進行比較,localeCompare()則是以當地的排序慣例為基礎進行比較.

a.用法,string.localeCompare("字串")
b.參數,指定參數的字就是要進行比較的字串
c.回傳值,
若字串string<參數的字串:傳回一個小於0的數
若字串string>參數的字串:傳回一個大於0的數
若字串string=參數的字串:傳回0
若依照當地的排序慣例,兩個字串没有區別,一樣傳回0.
d.例
var str=new String("革命舞曲‧穿心");
var str1="前奏曲‧破兵";
var str2="革命舞曲‧穿心";
document.write((str1<str2)+"<br>");//傳回true♨這...是比字數嗎?
document.write((str1>str2)+"<br>");//傳回false
document.write((str1==str2)+"<br>");//傳回false
document.write((str==str2)+"<br>");//傳回true
document.write(str1.localeCompare(str2)+"<br>");//傳回-1
document.write(str1.localeCompare(str)+"<br>");//傳回-1
document.write(str.localeCompare(str2)+"<br>");//傳回0
♨這樣到底要幹嘛?

----------------



七.Array物件

在JS中,Array其實就是一種特殊的物件,陣列擁有元素,就如同物件擁有屬性。
要宣告一個陣列就是建立一個Array物件。索引值由0開始。

1.陣列建構式
new Array()
new Array(n)
new Array(element0,element1...elementn)
#1.n值,n為預設的陣列元素個數,n的值即length屬性值
#2.element,兩個以上的參數,使用這些參數呼叫Array()建構式時,新建立的陣列元素會被初始化為這些值,length屬性值為參數的個數

(1).建立陣列物件
如:
var myArray=new Array(數值);
//參數的數值表示陣列的元素數目


(2).建立陣列後,就可指定值,指明即可,如:
myArray[0]="魯夫";
myArray[1]="羅賓";
myArray[2]="香吉士";

也可以在建立陣列時直接指定

var myArray=new Array("魯夫","羅賓","香吉士");

(3).陣列元素的存取

(a).一般想存取陣列內容,都會使用迴圈。如:
for(var i=0;i<myArray.length;i++){
document.write(myArray[i]+"<br>");
}
但要知道一個陣列的內容,直接write看看就可以知道了,write出來的情況是每個元素都會被列出,元素和元素間以小逗號「,」隔開。如:
document.write(myArray);

和使用(等一下會介紹到的)陣列物件內建的方法join()是一樣的。如:
document.write(myArray.join());

跟用迴圈也跑出來是一樣的,如:
for(var i=0;i<myArray.length;i++){
document.write(myArray[i]+",");
}

(b)要存取某一元素,指定索引即可
如:myArray[n];

(4).注意事項
(a).若呼叫Array()建構式時未使用參數,就會傳回空陣列,length屬性值為0
(b).若呼叫Array()時只傳給它一個數字參數n,則Array會傳回有指定個數元素值為undefined的陣列
(c).用指定的參數呼叫Array()時,Array()將用參數指定的值始化陣列.
(d).也可以不使用new運算子,作用與使用new運算子呼叫的作用完全一樣.
(e).若傳給Array()的整數參數n是負數,或大於232-1,將會丟出例外(RangeError).
(f).ECMAScript v3規定了陣列實字的語法,我們可以將運算式以逗號分隔置入中括號中,建立並初始化一個陣列,則運算式的值將會户為陣列元素.如
var a =[1,true,"abc"](數值,字串,陣列都可以)
var b =[a[0],a[0]*2,f(x)](陣列,函數,運算式也可以)

2.陣列物件的屬性

屬性說明
length取得陣列的元素個數


length屬性值是個可讀寫的數值(整數),指向陣列中元素的個數,若陣列中的元素不連續,length值就是此陣列中最後一個元素的索引值大1的整數,若改變length值將刪減或延長陣列.

3.陣列物件的方法

方法說明
join()將陣列的每個元素使用字串的方法顯示,元素和元素間以小逗號「,」隔開(當然要write出來看才得到,不是呼叫就會列出來。)
reverse()反轉陣列元素的順序,由尾到頭順序顯示,元素和元素間以小逗號「,」隔開(當然要write出來才看得到,不是呼叫就會列出來。)
sort()將陣列的所有元素進行排序
concat(陣列)將參數指定的陣列和目前的陣列合併


♨sort()方法,没有特別指明,預設就是按字母順序排列。若是數字,會按數字大小由小到大排,如1.2.3...也就是遞增排序(而且有點機車,經證實,如有20的話,20會排在3前面)。但若是中文呢?布魯克又不知道了...呵呵...待查。

♨可以自訂一些排序的函數,作為sort()方法的參數。聽說函數必須返回下列值之一:
(1)負值,如果所傳遞的第一個參數比第二個參數小。
(2)零,如果兩個參數相等。
(3)正值,如果第一個參數比第二個參數大。
為什麼呢?不知道。
如布魯克在網路上找來的這兩個函數
function desc(x,y){ //遞減
if (x > y)
return -1;
if (x < y)
return 1;
}

function asc(x,y){ //遞增
if (x > y)
return 1;
if (x < y)
return -1;
}
再write出來看看就可以知道了:
document.write(myArray.sort(desc));
//或
myArray.sort(desc);
document.write(myArray);


4.多維陣列
二維以上的陣列,JS裡並没有。

(1).JS裡並没有內建二維以上的陣列,不過我們仍可用第七章開啓陣列的方法,再開啓一個陣列後,再自己動手以手工的方式去開一個,就會造成二維陣列。如:

var myArray=new Array(數值1.);
for(var i=0;i< myArray.length;i++){
myArray[i]=new Array(數值2)
}

如此即可開啓一個數值1×數值2的二維陣列。
♨參第七章陣列

(2).要指定值時,再指明即可,如:
myArray[0][0]="魯夫";
myArray[0][1]="船長";
myArray[1][0]="香吉士";
myArray[1][1]="廚師";
....

八.Date物件

Date可以取得系統的時間和日期,且提供方法對間期和日期進行操作。


1.建構式
new Date()
new Date(n)//n表示毫秒
new Date("字串")//字串="month day, year hours:minutes:seconds"
new Date(yyyy,mm,dd,h,m,s,ms)//指年,月,日,小時,分鐘,秒,毫秒


new Date():不設參數,會傳回目前時間日期的字串,如:Mon Feb 18 14:00:00 UTC+0800 2008

new Date(n):參數n,單位毫秒,傳回指定參數的時間距1/1/1970午夜零點的時間(單位毫秒表示),如傳入2000,會傳回Thu Jan 1 08:00:02 UTC+0800 1970 ,即建立的Date物件代表1970年1月1日午夜過2秒

new Date("字串"):指定時間日期的字串,但格式必須要Date.parse()方法可以接受的.
var now=new Date("month day, year hours:minutes:seconds");
如:var now=new Date("Feb 18 2007");
document.write(now);//write出來是:Sun Feb 18 00:00:00 UTC+0800 2007
♨這樣要幹嘛???

new Date(yyyy,mm,dd,h,m,s,ms)//指new Date(年,月,日,小時,分鐘,秒,毫秒)

new Date(yyyy,mm,dd)

yyyy:四位數字,若寫2位數,就是19開頭的19yy,超過1999要寫全4位數,2001表示2001年
mm:0~12從0開始跳,0代表1月,11代表12月
dd:1~31,唯一一個從1開始跳的
hh:0~23
mm:0~59
ss:0~59
ms:0~999

(1).函數
Date()

不必new,Date()可以作為普通函數被呼叫,此時Date()會略傳給它的參數,傳回目前時間日期的字串.
如:Mon Feb 18 13:56:39 2008
直接呼叫就行了.
可以write看看:
var now=Date();
document.write(now);

document.write(Date());

(2)一般都是生出實體後,再去調用Date相關的方法
var myDate=new Date();

2.Date物件常見的屬性和方法
一般都是靠Date的方法操控Date物件,也只有Date物件才能使用Date方法,非Date型態的物件使用Date方法會丟出例外(TypeError)

(1).取得日期和時間

方法說明
getDate()/getUTCDate()傳回日期值1~31(採本地時間或世界時間,UTC:即GMT,指世界時間)
getDay()/getUTCDay()傳回星期值0~6(表星期日到星期六)
getMonth()/getUTCMonth()傳回月份值0~11(表1到12月)
getYear()傳回年份(若在1900~1999年間會傳回後兩碼,否則會傳回完整年份)
getFullYear()/getUTCFullYear傳回完整年份
getHours()/getUTCHours()傳回小時0~23
getMinutes()/getUTCMinutes()傳回分鐘0~59
getSeconds()/getUTCSeconds()傳回秒數0~59
getMilliseconds()/getUTCMilliseconds()傳回1/000秒為單位的秒數,0~999
getTime()傳回自1/1/1970年開始至今的的毫秒數.單位為1/000秒(毫秒)
getTimezoneOffset()傳回本地時間和UTC時間(格林威治標準時間)的時差的,單位為分鐘
注意,指定的日期若是夏令時間(日光節約時間daylight savings time)會影響回傳值.


(2).設定日期和時間

方法說明
setDate(n)/setUTCDate(n)設定Date物件的日期1~31
setMonth(n)/setUTCMonth(n)設定物件的月份0~11
setYear(n)設定物件的年份(在19901999間只需使用後兩位,否則要打出完整的年份)
setFullYear(n)/setUTCFullYear(n)設定Date物件的完整年份
setHours(n)/setUTCHours(n)設定物件的小時0~23
setMinutes(n)/setUTCMinutes(n)設定物件的分鐘0~59
setSeconds(n)/setUTCSeconds(n)設定物件的秒數0~59
setMilliseconds(n)/setUTCMilliseconds(n)設定物件的秒數,0~999(以1/000秒為單位)
setTime(n)自1/1/1970年開始,添加或減少設定的時間。(以1/000秒為單位)


1.3.其他日期和時間相關的方法

方法說明
toDateString()將Date物件的日期部分轉換為字串,傳回本地日期的字串(不含時間)如:Mon Feb 18 2008
toTimeString()將Date物件的時間部分轉換為字串,傳回本地時間的字串(不含日期)如:15:59:43 UTC+0800
toLocaleString()將Date物件轉為字串,採當地時間.傳回當地時間的字串
toLocaleDateString()將Date物件的日期部分轉為字串,採當地時間.傳回當地日期的字串
toLocaleTimeString()將Date物件的時間部分轉為字串,採當地時間.傳回當地時間的字串
toGMTString()將Date物件轉為字串,採世界時間.傳回轉換成GMT時間的字串
toUTCString()將Date物件轉為字串,採世界時間.傳回轉換成GMT時間的字串
toString()將Date物件轉換為字串,傳回的是本地時間的字串如:Mon Feb 18 15:52:21 UTC+0800 2008
valueOf()傳回 Date物件的原始值.和getTime()所顯示出來的值是一樣的,內部的毫秒格式



內部的毫秒格式:指距1/1/1970午夜至今的毫秒數.
使用最小單位使得對時間的操控變得容易,如:1ms*1000=1秒,1秒*60=1分,1分*60=1小時,1小時*24=1天.
所以使用毫秒可以任意地轉成1天,1周,1月,1年等.若我們求得一任一時間總量,只要除以(1000*60*60*24),就可以轉換成天.
♨聽說ECMAScript要求Date物件應能把1/1/1970後一億天中的任何日期轉換成毫秒,範圍在正負2735785年之間,所以JS的時鐘不會超275755年(人類還能活那麼久嗎?)
除了上述的實體方法之外,Date還定義了兩個靜態的方法:parse()和UTC().這兩個方法由建構式Date()本身呼叫,而不是由Date物件呼叫.


方法說明備註
Date.parse("字串")根據本地時間傳回1/1/1970到指定日期的毫秒數(單位1/1000秒)不必new
Date.UTC(yyy,mm,dd)根據世界时傳回1/1/1970到指定日期的毫秒数(單位1/1000秒)不必new



♨parse()和UTC()直接調用就可以了,算是類別方法吧。
parse("字串")是指:parse(years,months,days),如:parse("Feb,18,2007"),其中年月日的順序可以顛倒,分號(,)加或不加都無所謂.
UTC(n)是指:UTC(yyyy,mm,dd,hh,mm,ss,ms)如:UTC(2005,7,8),年月日必須,時分秒可選可不選,順序別顛倒.

如:var now=new Date();。document.write(Date.parse(now));。document.write(Date.UTC(now));


九.Math物件

Math物件是不必new的,直接調用就可以了。

1.Math物件的屬性

屬性說明
E2.71828...(=e)
LN20.69314...(=ln2)
LN102.30258...(=ln10)
LOG2E1.442695...(=log2e)
LOG10E0.43429448...=(=loge)
PI0.14159...(=π)
SQRT1_20.707106...(=√1/2)
SQRT21.414213...(=√2)



2.Math物件的方法(靜態函數)

方法說明備註
max(n1,n2)傳回兩數值裡的值大者(註1)
min(n1,n2)傳回兩數值裡的值小者
random()傳回亂數值傳回0.0~0.1之間的值
round(n)傳回數值四捨五入後的值
ceil(n)傳回大於等於參數的最小整數無條件進位
floor(n)傳回大於等於參數的最大整數無條件捨去
exp(n)自然指數en
log(n)自然對數0 < n,logen
pow(x,y)次方傳回xy
abs(n)傳回絕對值
sqrt(n)傳回平方根0 < n,傳回√n(註2)
sin(n)正弦函數(註2)
cos(n)餘弦函數
tan(n)正切函數
asin(n)反正弦函數-1 < n <1
acos(n)反餘弦函數-1 < n <1
atan(n)反正切函數
atan2(y,x)計算從x軸到一點的角度計算y/x的反正切值



(1)Math.max(n1,n2,...,n)
傳回最大的n,在ECMAScript v3之前這個函數只能有兩個參數,
若没有參數,會傳回Infinity,若有一個非數值參數,就傳回NaN.
Math.min(n1,n2,...,n)亦同

(2)Math.sqrt(n)
若n小於0,會傳回NaN.

(3)Math.sin(n)
n是以弧度表示.
角度*(2π/360)=弧度.

十.Error物件與錯誤處理

Error物件儲存著JS執行時所產生的錯誤訊息,JS執行時若有錯誤產生,Error物件的副本就會自動建立。

1.Error物件的屬性

屬性說明
number錯誤代碼(一個32bit的值,後面的16bit會顯示錯誤代碼的編號)
message錯誤訊息(儲存錯誤說明的字串)
descrption錯誤敍述(好像跟message差不多)


2.錯誤處理

(1).try{}敍述
(2).catch(變數){}敍述
(3).finally{}敍述

區塊中的程式碼就是要進行錯誤處理的程式碼。若有多層的話可以用throw指令,丟給外層的錯誤處理敍述去處理。「catch(變數){}敍述」中的參數可以接收Error物件的屬性,要顯示錯誤訊息的話,就用參數去調動如:catch(er){
敍述...;
}
document.write("錯誤代碼:"+(er.number&0XFFFF)+"<br>");
document.write("錯誤訊息:"+er.message+"<br>");
document.write("錯誤情況:"+er.descrption+"<br>");

3.Error物件
(1)建構式
new Error(|"字串")
Error()//函數
(2)參數,非必要參數,提供例外的額外資訊的字串
(3)回傳值,回傳一個新建的Error物件,若有設定參數字串,該Error物件將參數字串存為message屬性的值(也可能是一個空字串),否則就會用預設的字串作為該屬性的值,亦可單純以函數呼叫,效果與使用new是一樣的.
(4)常見的屬性和方法

屬性內容
name指出例外型態的字串
message例外的錯誤訊息資訊


方法內容
toString()

Error類別的實體表示錯誤或例外,常與throw和try/catch敘述一起使用,屬性name指出例外的型態,message提供可閱讀的詳細資訊.
JS的直譯器不會直接丟出Error物件,而是丟出Error子類別的實體(SyntaxError,RangeError等)
要顯示錯誤訊息,就是調用name和message屬性,而不是去呼叫toString.
(EMCAScript標準除了規定toString()回傳字串外,没有再作其他規定,特別是它不要求傳回的字串含有錯誤型態的名稱和訊息)

(5)例
//定義一個函數
function factorial(x){
if(x<0)throw new Error("x至少必須大於0");//限制x至少必須大於0
if(x<=1) return 1;else return x*factorial(x-1);
}

(5.1)傳入負數(有時,有些東西是不可能負的)
try {factorial(-1/*an error is thrown here*/)}//傳入-1
catch(e){
if(e instanceof Error){//它是一個Error或子類別的實體嗎?
document.write(e.name+":"+e.message);
}
}//顯示:

(5.2)傳入不同的資料型態(結果,奇怪,竟然還真的在跑?,大概是函數設計還不夠周延,但因為是個遞迴,最後堆疊不足)
try {factorial("喲~~~"/*an error is thrown here*/)}//傳入字串(故意找碴)
catch(e){
if(e instanceof Error){
document.write(e.name+":"+e.message);
}
}//顯示:

(5.3)没有宣告函數hoho()
try {var x = hoho()}
catch(e){
document.write(e.name+":"+e.message);
}//顯示

(5.4)用eval()測試,確實要傳入字串的,但傳入的東西它没法算
try { eval("&*&")}
catch(e){
document.write(e.name+":"+e.message);
}//顯示

4.EvalError
不正確使用eval()時丟出(還没見過)
(1)建構式
new EvalError(|"字串")
EvalError(|"字串")//函數
(2)參數,非必要的參數字串,,提供例外的額外資訊
(3)回傳值,回傳一個新建的EvalError物件,若有設定參數字串,該Error物件將存為message屬性的值,否則就會用預設的字串作為該屬性的值,亦可單純以函數呼叫,效果與使用new是一樣的.
(4)常見的屬性和方法,(同Error物件)name,message,toString()

5.RangeError
數字超出合法範圍時丟出
如:把陣列length屬性值設成負數
(1)建構式
new RangeError(|"字串")
RangeError(|"字串")//函數
(2)參數,非必要的參數字串,,提供例外的額外資訊
(3)回傳值,回傳一個新建的RangeError物件,若有設定參數字串,該Error物件將存為message屬性的值,否則就會用預設的字串作為該屬性的值,亦可單純以函數呼叫,效果與使用new是一樣的.
(4)常見的屬性和方法,(同Error物件)name,message,toString()

6.ReferenceError
讀取不存在的變數時丟出
(1)建構式
new ReferenceError(|"字串")
ReferenceError(|"字串")//函數
(2)參數,非必要的參數字串,,提供例外的額外資訊
(3)回傳值,回傳一個新建的ReferenceError物件,若有設定參數字串,該Error物件將存為message屬性的值,否則就會用預設的字串作為該屬性的值,亦可單純以函數呼叫,效果與使用new是一樣的.
(4)常見的屬性和方法,(同Error物件)name,message,toString()

7.SyntaxError
語法錯誤時丟出
(1)建構式
new SyntaxError(|"字串")
SyntaxError(|"字串")//函數
(2)參數,非必要的參數字串,,提供例外的額外資訊
(3)回傳值,回傳一個新建的SyntaxError物件,若有設定參數字串,該Error物件將存為message屬性的值,否則就會用預設的字串作為該屬性的值,亦可單純以函數呼叫,效果與使用new是一樣的.
(4)常見的屬性和方法,(同Error物件)name,message,toString()

8.TypeError
當數值的型態錯誤
(1)建構式
new TypeError(|"字串")
TypeError(|"字串")//函數
(2)參數,非必要的參數字串,,提供例外的額外資訊
(3)回傳值,回傳一個新建的TypeError物件,若有設定參數字串,該Error物件將存為message屬性的值,否則就會用預設的字串作為該屬性的值,亦可單純以函數呼叫,效果與使用new是一樣的.
(4)常見的屬性和方法,(同Error物件)name,message,toString()

9.URIError
若指定的字串含有不合法的16進位跳脫序列,encodeURI()或decodeURI()就會丟出.
若指定的字串含有不合法的替代對(surrogate pair)encodeURI()或decodeURI()也會丟出.

(1)建構式
new URIError(|"字串")
URIError(|"字串")//函數
(2)參數,非必要的參數字串,,提供例外的額外資訊
(3)回傳值,回傳一個新建的URIError物件,若有設定參數字串,該Error物件將存為message屬性的值,否則就會用預設的字串作為該屬性的值,亦可單純以函數呼叫,效果與使用new是一樣的.
(4)常見的屬性和方法,(同Error物件)name,message,toString()

十一.Regexp正規運算式

1.正規運算式Regexp(regular expression;RE),正規表示式,正則表達式...譯名很多.

Regexp規則表達式,(以下用//來表達)就是一套規則啦,用來描述字元樣式(Pattern;花樣,形態)的規則.
就是說呢,JS除了String物件可以用來處理字串外,還引用了Regexp,可以用規則表達式的形式,對文字樣式作樣式比對(Pattern matching).如一般在文字中最常見的搜尋,替換,其實就是Regexp的拿手好戲.
♨規則表達式,的的確確是一種運算式,或說是表示法(跟其他語言標準比起來,没有其他語言該有的特徵,還稱不上是一種語言).聽說是JS偷自Perl的,是Perl的Regexp中的一部分.Regexp在不同版本的實作中都不完全相同,但既然JS是採用perl的Regexp,完整的Regexp語法,要參考perl.不過...必要性似乎没那麼大,因為JS只採用了perl部分的Regexp.所以看JS採用哪些應該就行了.
支援Regexp的當然不止JavaScript,除了Perl外,python,VBScript,php,asp,Java,C#,MySQL也都支援.


1.RE的文字字元(Characters;一般字元;文數字元1)

在Regexp環境裡,依字元有無特殊意義來分,一般有兩種
(1).Characters(一般字元;文數字元):代表的意義與原來字面上的意義相同
(2).Operators(特殊字元;非一般字元):具有某種特殊的意義,要使其恢復原來字面上的意義,就要使用跳脫字元「\」(反斜線).
與其他的語言一樣,在Regexp裡有些符號代表特殊意義如:
.,^,&,*,+,?,=,!,:,|,\,/,(),[],{},<,>
而Regexp就是由這些符號與其餘的字文數字元組成.

(1)RE的一些特定格式的字元
有依照字面意義的一般字元,加上利用跳脫字元回復其字面意義特殊字元,所有可以表達的字元大約都齊全了.
不過還有一些特定格式的字元如下.
所有抬面上的字元都有了,還有什麼字元呢?聽說是有的...如換行\n,也就是說它可以比對一個換行符號,但換行符號又是什麼符號呢???没有!所以就要藉助跳脫字元的幫助來表示

字元格式備註
\oNUL字元(\u0000)
\t水平定位(Tab鍵;\u0009)
\n換行(New line;\u000A)
\v垂直定位(\u000B)
\f換頁(下一頁;\u000C)
\r游標歸位(Carriage return(CR);游標返回;\u000D)
\xXX由兩位數的十六進位數XX定義的拉丁字元(如:\x0A等同\n)
\uXXXX由四位數的十六進位數XXXX定義的Unicode字元(如:\u0009)
\cX控制字元^X(如:\cJ等同於\n)
[...]表任意一個在[]集合中的字元以下是字元集合
[^...]表任意一個不在[]集合中的字元以下是字元集合
\w任意一個(ASCII)文字字元(字母及數字),等同於 [a-zA-Z0-9][...]的簡寫
\W任意一個非文字字元(字母及數字),等同於[^a-zA-Z0-9][...]的簡寫
\s任意一個(Unicode)空白字元,等同於[ \f\n\r\t\v][...]的簡寫
\S任意一個非空白字元,等同於 [^\f\n\r\t\v][...]的簡寫
\d任意一個(ASCII)數字,等同於[0-9][...]的簡寫
\D任意一個非數字,等同於[^0-9][...]的簡寫
\b比對一個單字的邊界,也就是指單字和空格間的位置
\B比對非單字的邊界
[\b]倒退鍵(Backspace鍵)特例

♨參考跳脫字元

2.RE的特殊字元(Operators)


字元格式備註

\反斜線.跳脫字元,將特殊字元還原成字面意義,或標記成特殊字元的字元.如/\n/表換行字元而/3.14/因為/./有特殊用途了,表萬用字元,應該跳脫出來,要比對3.14應是/3\.14/

.實心句號.萬用字元,代表任意一個字元.

^克拉(carat).限制字串必須出現於行首,比對字串的開始位置.如:
/^A/表比對開頭是A的字串
(在字元集合中表示「非」,「not」)

$金錢號.限制字串必須出現於行末.比對字串的結束位置如:
/t$/表比對結尾是t的字串


|豎分號(pipe).表示邏輯上的 "或(or)",.如:
/x|y|z/表比對x或y或z其中任何一個


-短破折號(dash).(在字元集合中)用來指定字元的區間(範圍)

()小括號.分組,用以括住一群字元,且將之視成一個group

[]中括號.字元集合, 用以表示兩中括號間 所有的字元當中的任一個.如:
/[0123456789]/表示0,1,2,3,4,5,6,7,8,9這個集合中的任一個字元.(指任何一個數字,等同/[0-9]/).


*星號.表示(其前的字元或字元集合)可重複出現0次以上的任意次數(一次都没有,一次,或一次以上).如:
/0*36/可以比對36、036、0036、00036.../ab*/可表示a、ab、abb、abbb、.../[0-9]*/表示前面的阿拉伯數字可以不出現或出現任意多次.
等同{0,}
以下是次數控制(重複比對)

+加號.限定(其前的字元或字元集合)至少出現一次(含一次或一次以上).如:
/goo+gle/可以比對google,gooogle,goooogle,...等
等同{1,}

?問號.限定(其前的字元或字元集合)最多可出現一次(含一次或一次都没有)表示非必須的.如:
/colou?r/可以比對colour或者color.
等同{0,1}

{}大括號,表示(其前的字元或字元集合)出現的次數

{n}正整數n表次數,指定比對{}前面的字元或字元集合須重複出現n次.如:
/a{2}/表示指定a這個字須重複出現2次./ap{2}/表一個a之後再接上2個p所組成的字串


{n,}正整數n表下限次數,指定比對{}前面的字元或字元集合須重複出現n次以上(含n次).如:
/g{2,}/表示指定g這個字須重複出現2次以上./go{2,}/表一個g之後再接上2個以上的o所組成的字串


{n,m}正整數n,m分別表下限和上限次數,指定比對{}前面的字元或字元集合須重複出現n次到m次.如:
/0{2,4}/表示指定0這個數字重複出現2到4次./[0-9]{2,4}/表任一個數字須重複出現2到4次,





3.RE的修飾子(Modifiers;旗標flags)

g全域比對(global match)
i不分大小寫(ignore case)
m多行模式
s單行模式
x擴充語法

(1)字元集合(中括號[];character class)

a.[]
將個別的文字字元放在中括號中,就形成一個字元集合.
字元集合會比對任何一個置於中括號中的字元.
如/[abc]/會比對a,b,c中的任何一個

b.-
也可以在字元集合中使用短破折號「-」界定一個範圍
如/[a-z]/就代表所有的小寫字母,/[a-zA-z0-9]/表示所有的英文字母和數字

c.^
也可以定義字元集合的差集.在字元集合中將「^」(carat)符號置於前端,作為中括號中的第一個字元.
如/「^abc」/表示abc以外的任何字元

d.有些常用到的字元,重複率很高,所以有定義簡截寫法,如:\s(空白),\w(文字),\d(數字)...等.(swd)
以\s為例,\s表示空格,包含所有的空格(游標歸位,換行,換頁,水平定位,垂直定位...等等等)真的要寫出來就是:/[\f\n\r\t\v]/,若每次都要nfrtv大概會抓狂.所以就定義了/[\s]/(超級用法?).而它的差集就寫大寫/[\S]/就好了.同理[\w]就是所有的文字,[\d]就是所有的數字,而它們的差集就是大寫.
e.唯一麻煩的\b,它是個特定格式的字元,代表邊界.
但若它在字元類別裡代表的是倒退鍵,所以要在規則表達式中表現倒退字元,就要用/[\b]/

(2)重複比對(大括號{})
要比對任一個意義等同於字面的文數字,這我們會嘛...就指定要比對的文數字就行了.
有中括號界定出class,要比對當然就更輕鬆了.
但若一個字,裡頭的字元重複出現n多次,如gooooooooooooooogle指定起來大概也是會抓狂.
又如/\d/表0到9的任一數字,/\d\d/可以表示一個二位數,可用/\d\d\d\d/表示一個四位數字
但若要描述一個“任意位數”的數字,怎辦?好像没辦法.
這些複雜的樣式,就可以用重複比對來完成.

a.重複比對(/{}/)可以指定某一字元重複出現幾次.在{}前面的字元就是{}作用的字元.(只有前面那個字元喔)
如:/\d{2}/指這個任意數字重複出現兩次,相當於/\d\d/,表示二位數
/\d{2,4}/指這個任意數字重複出現二到四次,表示二到四位數
/\d{1,}/指這個任意數字至少重複出現一次以上,表示一個任意位數的數字
/\w\d{2}/表示一個任意文字字元後面有9數字

b.有些經常用到(或說簡單的)次數指定,也定義簡截式如:「*」,「+」,「?」(*+?)
以問號為例,經常見到的例子是/colou?r/,因為colour和color是一樣的,也就是說u這個字元出不出現都無所謂,是非必須的意即/ colou{0,1}r/.但若遇到這種情況,每次都去打{0,1}而不抓狂,想來也很難.所以就打問號就行了,變成/colou?r/.
同理「*」,「+」也一樣
如:/\w{3}\d?/:表示三個文字字元,和一個非必須的數字
/\s+java\s+/:表示字串“java”前後有一個或很多個空白
/[^"]*/:表示没有或有很多個非引號的字元

c.貪婪的重複比對
以上的重複字元會依照我們的指定,去比對盡可能多的字元,而且允許接下來的規則表達式繼續比對下去.
所以稱這個重複比對是「貪婪的」(Greedy).

d.非貪婪的重複比對
在JS1.5以後,支援非貪婪的重複比對,只要在重複比對的符號後追加個?即可.
如:「*?」,「+?」,「??」,{n,m}?

(3)選擇符號(豎分號「|」)
豎分號「|」這個字元分隔了可供選擇的項目,表示「或(or)」
如./ab|cd|ef/表比對字串“ab”或“cd”或“ef”
/\d{3}|[a-z]{4}/表比對三位數字或四個小寫字母

a.當從左至右搜索時,若前面的選擇樣式巳經相符,它就忽略後邊的樣式,即便還會有更好的比對結果.所以若將樣式/a|ab/套用在字串“ab”時,它只會符合第一個字元.

(4)分組符號(小括號「()」)
a.小括號可以將將個別項目包起來,組成一個子運算式(subexpression;次表達式)
則小括號的內容,就會被其他特殊字元*,+,?等視作一個單位(group).
如./java(script)?/,則會比對“java”或“javascript”, script就可有可無,
如/(ab|cd)+|ef/就會比對“ef”,及出現一次以上的“ab”或“cd”.

b.用小括號包裹的子運算式,可以被標誌,以便之後參考
用小括號的另一個作用是,我們在同一個正規運算式裡,
可以再度參考,方法是用反斜線加上數字來指定.
\1代表第一個子運算式,\2代表第二個.
注意,由於子運算式可以巢狀,要算位置是以左小括號為準,
如以下的規則運算式,包在裡頭的子運算式是以\2來表示
/([Jj]ava([Ss]cript)?)\sis\snot\s(fun\w*)/

c.小括號可將個別項包起來,用來定義一個子樣式
表達式比對到了一個目標字串後,我們可以在目標字串中擷取出,符合任何加了括號的子樣式部分.
如/[a-z]+\d+/,可以比對一個以上的小寫字母,後面跟著一個以上的數字.
此時若我們只想要知道每個相符字串後面掛著的那串數字,就可以把那部分用小括號包起來.
變成/[a-z+](\d+)/,則可將數字從符合結果中取出來.



d.指向規則表達式的前一個子表達式,並不代表該子運算式的樣式,而是符合樣式的文字內容.
所以參考指標並不只是一個簡便的工具,除了讓我們不必鍵入規則表達式重複的部分,
它還產生一種限制,把字串中包含的字元完全相同的部分分開.
如:規則表達式/['"][^'"]*['"]/
表示符合任何一個加上單引號或雙引號的字元,
但它並不要求前後的引號種類要一致,要規定前後引一號一致,我們可以用一個參考指標
變成:/(['"])[^'"]*\1/

\1相對於任何符合第一個加括子運算式的東西,在此例中它還產生一佪限制,就是結尾的引號和開頭的相符.
規則表達式不允許用雙引號括起的字串中有單引號,反之亦然.
在字元類別中使用參考是不合法的,所以我們不能編寫/((['"])[^\1]*\1/這種表達式.

e.在JS1.5中,不必建立巳編號的參考指標即可以將規則運算式的項目分組,且不會產生參考指標
並不是單純用了小括號分組,而是用「(?」和「)」來分組.
如:/([Jj]ava(?:[Ss]cript)?)\sis\snot\s(fun\w*)/
在此例,子運算式(?:[Ss]cript)只用於分組,因此?重複比對字元可套用到各個分組.
這種改良的括弧並不產生參考,所以在此規則運算式中,\2會參考與(fun\w*)相符的文字

(3)錨點(anchor)
相對於規則運算式的特殊字元和文數字元,還有一種特定格式的字元,可用來比對字元間寬度為0的空間.這些特定格式的字元稱作錨點,因為它們把樣式定位在比對字串的特定位置,而不是用來比對真實的字元.
常見的有「^」,「$」,「\b」,「\B」
如:\b用來比對文字字元和文字字元之間的邊界.
要比對文件中“java”這個字,可以用/\sjava\s/,但這樣可能會有兩個問題,
一.若有個“java”在字串的開頭或結尾,它就不會被比對到.因為它的前後没有空白.二.如果這樣真的找到一個相符的字,它傳回的字串會包含前後的空白,這種情形可能不是我們要的.此時就可以試試/\bjava\b/
若要尋找一行文字本身要符合“JavaScript”這個字,可以用/^JavaScript$/

a.在JavaScript1.5中還可以用其他的正規運算式作為錨點條件.
常見的有「(?=n)」,「(?!n)」
如在符號(?=)的等號後面指定字元,限定前面的字串後面所接著的是符合指定的字元.但它本身不會被比對到.如:我們要比對一種常用的程式語言名稱,但限定只有其後有冒號時相符,可以用/[Jj]ava([Ss]cript)?(?=\:)/♨冒號要跳脫嗎?,則這個樣式與“JavaScript:is not fun”中的“JavaScript”相符但與“Java is fun”中的“Java”不相符,不是因為它後面没有“Script”,而是“Java”後面没有冒號.
符號(?=)的反面是(?!),在驚嘆號後指定字元,限定前面的字串後面所接著的不能是我們指定的字元.
如/Java(?!Script)([A-Z]\w*)/會比對“Java”後面接著一個大寫字母和任意多個(ASCII)字元,但就是不能接著Script.它與“JavaBeans”相符,但不與“Javabean”相符(Java後面不是大寫開頭),與“JavaScrip”相符,但不與“JavaScript”及“JavaScripter”相符(Java後面不能是“Script”)

(4)修飾子(Modifiers)
或稱旗標(flags)加在運算式後面,用來加強限制,但並非必需的,在使用上可以重複使用
常見的有「i」,「g」,「m」
「i」,忽略大小寫,表示無大小寫之分的比對
如:若要找“java”這個字,不分大小寫(java或JAVA),且要找到這佪字在字串中所有出現的位置,可以用/\bJava\b/i
「g」,全域比對,
如:若要找“java”這個字第一次出現的位置,不分大小寫(java或JAVA),可以用/\bJava\b/i
「m」,多行模式,在多行模式中若要尋索的字串中含有換行符號,錨點^和$除了比對字串的開頭和結尾外還比對每行的開頭和結尾,如:/Java$/im會符合“java”和“java\nis not fun”

4.JS不支援的Perl RegExp
(1)特定格式字元:\a\A\e\E\l\L\u\U\z\Z\Q\G
(2)錨:(?<=)(?<=!)
(3)修飾子:s,x

5.RegExp物件

(1)建構式
new RegExp(regexp|"regexp",修飾子)
RegExp(regexp|"regexp",修飾子)//函數
var pattern=/regexp/g|i|m;//實例,直接指定
var re=new RegExp(regexp|"regexp",g|i|m)//實例

(2)參數
第一個參數是規則運算式或規則運算式的字串,
第二個參數是修飾子g,i,m,非必要參數,若第一個參數是規則運算式而不是字串,必須省略.

(3)回傳值,傳回以指定樣式產生的RegExp物件.
若是單純的函數呼叫,效果跟RegExp一樣,但若第一個參數是規則運算式而不是字串,
它就只傳回樣式,不新建RegExp物件.

(4)丟出
(a)SyntaxError,若第一個參數不是合法的規則運算式,
或第二個參數含有g,i,m之外的字元,會丟出SyntaxError
(b)TypeError,若第一個參數是規則運算式,而第二個參數没有省略,會丟出.

(5)RegExp物件常見的屬性

global全域比對,檢查RegExp物件是否具有特性g
ignoreCase忽略大小寫,檢查RegExp物件是否具有特性i
multiline多行模式,檢查RegExp物件是否具有特性m
lastIndex上次比對後的字元位置,用於在一個字串中進行多次比對
source規則運算式的文字來源



(6)RegExp物件常見的方法


exec()通用的樣式比對
test()檢測字串是否符合個樣式
toString()將規則運算式轉成字串


a.global屬性
是個唯讀的布林值,檢查是否執行區域比對(即建立RegExp物件時是否了特性g)
(a)用法,regexp.global

b.lastIndex屬性
下次比對的起始位置
(a)用法,regexp.lastIndex

(b)是個可讀寫的屬性,對於有設定g特性的規則運算式來說該屬性存放的是一個整數,
它指定緊接著上次找到的相符文字的字元位置.
(c)上次比對的結果是由RegExp.exec()或RegExp.test()找到的,
(d)它們都以lastIndex屬性所指的位置作為下次搜尋的起始點.
如此則我們就可以透過反覆呼叫這兩個方法來遍覽字串中所有相符的文字.
(e)不具有特性g和不代表全域樣式的RegExp物件不能使用lastIndex物件.
(f)因為這個屬性是可讀寫的,所以只要目標字串的下一次搜索開始就可以對它進行設定,
當exec()或test()再也找不到相符的文字時,它們會自動將lastIndex屬性重設為0,
若在成功的比對某個字串之後就開始搜尋另一個字串,需要明確地把這個屬性設為0.

c.source屬性
規則運算式的文字
是個唯讀的字串,裡頭存放RegExp樣式的文字,(不包含正斜線和特性g,i,m)
(a)用法,regexp.source
(b)例
var pattern=/\bJava\w*\b/g;
var text="JavaScript is not more fun than Java or JavaBeans";
var result=pattern.exec(text);//若無這一行,即没有調動RegExp兩大方法之一,lastIndex屬性就是0

if(pattern){
document.write("global屬性放的是:"+pattern.global+".(表是否啟用全域模式)<br>")
document.write("ignoreCase屬性放的是:"+pattern.ignoreCase+".(表是否忽略大小寫)<br>")
document.write("multiline屬性放的是:"+pattern.multiline+".(表是否啟用多行模式)<br>")
document.write("lastIndex屬性放的是:"+pattern.lastIndex+".(表下次搜尋的位置)<br>")
document.write("source屬性放的是:"+pattern.source+".(表指定的規則運算式)<br>")
document.write("以toString()方法調出來是:"+pattern.toString()+".<br>")
}else{
document.write("没有搜到相關的字串");
}
//顯示


d.exec()方法
通用的樣式比對
d1.在所有RegExp及String相關的樣式比對方法中,
exec()的功能最強大,是個通用的方法,但使用起來也最複雜.
exec()會搜索字串string,從中找出與指定的規則運算式regexp相符的文字,
若exec()比對到相符的字串,就會傳回儲存結果的陣列,否則傳回null.

d2.這個回傳陣列的第0個元素就是與運算式相符的文字,
第一個元素是與regexp的第一個子運算式相符的文字(若存在的話)
第二個元素是與regexp的第二個子運算式相符的文字,依此類推.

d3.這個回傳陣列通常有以下屬性

length指陣列中的元素個數
index指相符文字的第一個字元之位置
input指字串string



d4.若呼叫exec()方法的是非全域的RegExp物件,
傳回的陣列與string.match()傳回的陣列相同.(陣列的特性就如同上面說的那樣)

d5.若是全域的RegExp物件呼叫exec()方法,
它會在regexp的屬性lastIndex指定的字元位置開始搜索字串string.
當它比對到與regexp相符的文字時,會把regexp的lastIndex屬性設為相符文字的第一個字元位置.
所以,就可以反覆地呼叫exec(),遍覽子字串中的所有相符文字.
當exec()再也找不到相符的文字時,就會傳回null,且將lastIndex屬性重設為0.

d6.在另一個字串中完成一次樣式比對之後,要開始搜尋新的字串,就必須手動把lastIndex屬性重設為0

d7.但無論是否是全域樣式,exec()都會將完整的細節加到它傳回的陣列中,這點和
String.match()不同,實際上,
在迴圈中反覆呼叫exec()是唯一取得全域樣式的完整樣式比對資訊的方式.

(a)用法,regexp.exec("字串")
(b)參數,要搜尋的字串
(c)回傳值,存放比對結果的陣列,若没有找到相符的字串,其值為null.
(d)丟出,TypeError,呼叫此方法的物件不是RegExp時會丟出.

(e)例
var pattern=/\bJava\w*\b/g;
var text="JavaScript is not more fun than Java or JavaBeans";
var result;

while((result=pattern.exec(text))!=null){
document.write("比對到字串:'"+result[0]+
"'在位置"+result.index+
"下一次的搜尋在位置"+pattern.lastIndex+"<br>"
);
}
//顯示


e.test()
檢測字串是否符合指定的樣式
(a)用法,regexp.test("字串")
(b)參數,要檢測的字串
(c)回傳值,若字串中含有與regexp相符的字串,就傳回ture,否則傳回false.
(d)丟出,TypeError,呼叫這個方法不是RegExp時會丟出.
(e)例,
var pattern=/java/i;



十二.JavaScript的內建物件的共用屬性和方法

RegExp物件後述。在此載一些JS內建物件常見的共用屬性和方法。

1.常見的共用屬性

屬性說明
constructor



2.常見的共用方法。

方法說明
toString()傳回物件的內容,以字串表示
valuOf()傳回物件內容的值.



第九章 JavaScript的瀏覽器物件

一.window物件
代表瀏覽器的視窗(或框架).
1.window物件提供了一些屬性和方法,可以讓我們操縱瀏覽器視窗(或框架).
a.用法
window
self
window.frames[i]
2.也使用了一些屬性來定義其他瀏覽器中的物件.如document屬性指的即是document這個物件.
3.因為每個JavaScript程序一定會有一個廣域(/全域)物件,是整個程序作用範圍源頭,廣域物件的屬性就是廣域(/全域)變數。而window物件就是客戶端JavaScript的廣域物件。所以下面這兩行程序指的其實是一樣的事:
var recall=0; //宣告一個(全域)變數,且初始化
window.recall=0; //建立一個新的windows屬性

4.因為在html中,視窗和框架的地位是一樣的嘛.常出現JavaScript程序使用了多個框架,有的還使用了多個視窗,所以在每個JavaScript程序的視窗或框架都有自己的window物件.所以呢,在JavaScript的一個框架所宣告的全域變數,在另一個框架裡並不是全域變數,不過要取得在別的視窗(或框架)中定義的變數,還是可以取得的.

5.window物件常見的屬性及方法.


window物件常見的屬性
屬性表示備註
*window指目前的視窗
*navigator包含瀏覽器的所有資訊如類型,版本等
*screen包含螢幕的相關的資訊如螢幕大小等
*document指視窗中的文件
*history指使用者在視窗中的瀏覽記錄
*defaultStatus/status可讀寫的字串,狀態列的顯示文字(註:超連結標籤<a>使用的話,必須傳回true,才能發生作用.)
*closed唯讀的布林值,若該視窗是關閉的,值為true
*opener指開啟該視窗的,若是使用者開啟該視窗,opener的值是null.
*name指視窗的名稱(和框架的name作用一樣,要指定時就用得到)
*frames[]其中的window物件代表在該視窗中的框架
*parent代表包含它的框架
*top指包含它最上層框架
*self自我參考,和window同義.指目前的視窗
*length陣列frames[]中的元素個數,指視窗或框架包含的框架個數
*location物件*指出視窗中文件所在的URL(在document中也有個location)
frameElement(待查?)

Image物件IE,*奇怪,IE有耶,不是在document中嗎?
event
clientInformation

*scrollbarsNetscape
scrollX
scrollY
*screenX
*screenY
*innerWidth
*innerHeight
outerWidth
outerHeight
*pageXOffset
*pageYOffset
scrollMaxX
scrollMaxY
fullScreen
crypto
*menubar
*toolbar
*locationbar
*personalbar
statusbar
content
directories





window物件常見的方法
方法表示備註
*alert("字串")只有確定按鈕的警示窗

*confirm("字串")確定或取消按鈕的警示窗
*prompt("字串")要求使用者輸入資訊的對話方塊
*open()開啟新的視窗會傳回代表新視窗的window物件(URL,字串,字串,布林)
♨1.URL:新視窗文件的URL
2.字串:視窗名稱,若指定的名稱是巳開啟的視窗,就會直接使用該視窗,而不會再新增一個
3.字串:指定視窗要包含的GUI附加功能,瀏覽器的零件如設定網址列,功能列(menubar),
工具列(toolbar),狀態列(status),滾動條(scrollbar),寬(width),高(height),
重置尺寸(resizable),定位(location),目錄(dirctories),複製歷史(copyhistory)等.
經由一串由逗號相隔的列表來定義,1或yes表示允許
4.布林值:只有指定的視窗名稱是個巳存在的視窗時有用,ture表示第一個參數指定的URL會在瀏覽紀錄中取代現有的URL,false表示會在瀏覽紀錄中產生一個新的項目
♨open()就是window.open()。若真的要開一個新視窗,
就寫成window.open(),
因為document也有open(),
有時只寫說*open(),它可能會開一個新文件,而非新視窗.

*close()關閉視窗close();即window.close()可以關閉視窗
*focus()要求該視窗成為鍵盤輸入的焦點待查?
*blur()取消該視窗成為鍵盤輸入的焦點待查?
moveTo()移動視窗moveTo(n,n);會將視窗的原點(左上角)移到指定的座標
moveBy()移動視窗moveBy(n,n);會將視窗依指定的像素距離左右,上下移動視窗
*resizeTo改變視窗尺寸resizeTo(n,n);
*resizeBy()改變視窗尺寸resizeBy(n,n);
print()列印(視窗或框架中的內容)等同點擊瀏覽器中的列印按鈕
scroll()捲動視窗中顯示的文件
*scrollTo()捲動視窗中顯示的文件scrollTo(n,n);捲動視窗中的文件到指定的位置
*scrollBy()捲動視窗中顯示的文件scrollBy(n,n);左右或上下捲動視窗中的文件若干像素
*setinterval()設定在某時間間隔,重覆執行某函數
*clearInterval()取消在某時間間隔,重覆執行某函數
*setTimeout()設定在某時間(毫秒)後,執行某涵數
*clearTimeout()取消在某時間(毫秒)後,執行某涵數

*navigate()載入並顯示指定的URL

*back()回上一頁,等同按瀏覽器的Back鈕Netscape
*forward()下一頁,模擬瀏覽器的Forward鈕
*home()首頁,模擬瀏覽器的Home
*stop()停止,模擬瀏覽器的Stop
*captureEvents()捕捉事件,指定接發給該視窗的事件型態
*releaseEvents()釋放事件,指定不再捕捉的事件型態
*routeEvent()將事件Event傳遞給下一個接收事件的處理程式
setResizable()待查?
scrollByLines()待查?
scrollByPages()待查?
find()待查?






window物件常見事件處理器
物件表示備註
*onerror當發生JS錯誤時呼叫
*onresize當調整視窗大小時呼叫
*onblur當視窗失去焦點時呼叫
*onload當文件完全被載入時呼叫
*onfocus當視窗取得焦點時呼叫
*onunload當瀏覽器離開目前文件時呼叫
*onmove當移動視窗時呼叫聽說限Netscape4,但IE也有

onhelpIE
onscroll
onbeforeunload
onafterprint
onbeforeprintNetscape




二.navigator物件
包含瀏覽器的所有資訊如類型,版本等

2.一些常見的屬性
♨因為每個人的瀏覽器都不一樣,所以顯示出來的資訊也不會一樣.所以...全部查出來也没有義意.



navigator物件常見的屬性
屬性表示備註
*appCodeName瀏覽器的代號
♨聽說是開發商的內部代碼,布魯克看到的是Mozilla,為什麼用IE卻看到Mozilla???嘿嘿嘿...我不知道。但這不重要,因為除此之外這個屬性並没有提供額外的訊息。Mozilla就Mozilla吧,不知道就算了。

*appName瀏覽器名稱
♨這次看到的是IE没錯;Microsoft Internet Explorer

*platform瀏覽器執行的平台,瀏覽器所在的作業系統類別
*appVersion瀏覽器版本♨顯示的是"內部"版本號,"內部的",所以不必然與使用者取得的版本一致,像布魯克用IE6,看到的4.0,IE4~IE6都是4.0
*userAgent聽說是一個瀏覽器以HTTP標頭的user-agent送出的字串,這個屬性包含了appName和appVersion裡的的所有資訊.
*cpuClass
/oscpu
cpu的類型IE用cpuClass,Netscape是用oscpu,但兩者記載內容不一樣
*userLanguage
/language
使用者使用的語言(瀏覽器預設的語言),通常是兩個字母,如en表英語,fr表法語,或五個字母的字串,前面是語系後面是地域如fr-CA表法語系加拿大地區IE特有,Netscape是用language
*mimeTypes陣列中的元素代表瀏覽器支援的一種MIME型態,如text/heml或image/gif
*onLine是否在線(布林)
*cookieEnabled是否啟用cookie(布林)

*systemLanguage操作系統使用的語系IE特有,使用的程式碼就是Netscape的language的程式碼
*appMinorVersion副版本號(不太清楚)IE
*plugins[]陣列中的元素表示瀏覽器巳經安裝的外掛,Plugins物件提供有關外掛程式的資訊Netscape



(註)plugin(外掛):就是瀏覽器用以在視窗中顯示特定資型態的套裝軟體



navigator物件常見的方法
方法表示備註
javaEnabled()是否啟用Java
taintEnabled()待查?
preference()待查?
registerContentHandler()待查?
registerProtocolHandler()待查?

plugins.refresh()檢測新安裝的外式,將它插到plugins[]陣列中,並使用這些外程式有選擇地重新載入文件,使新安裝的plugins可以運作Netscape




3.實例






三.screen物件

2.一些常見的屬性


screen物件常見的屬性
屬性表示備註
width提供使用者螢幕大小的資訊,表示螢幕寬(px)
height提供使用者螢幕大小的資訊,表示螢幕高(px)
availWidth表示真正可用的螢幕寬(px)
availHeight表示真正可用的螢幕高(px)(如windows中,工具列所佔用的空間就會被扣除)
colorDepth以2為底表示可顯示色彩數的指數.
一般這個數字和螢幕每像素用的位元數一樣,如8位元可顯示256色(2的8次方).(若這些顏色都可以被瀏覽器使用,screen.colorDepth屬性的值就是8.)
pixelDepth瀏覽器的顏色深度
topY軸的起始座標
leftX軸的起始座標
availTop螢幕最頂部的Y座標(不含工作列)
availLeft螢幕最左側的X座標(不含工作列)




四.location物件
視窗的location屬性是指向location物件的參考
location物件代表目前視窗所顯示文件的URL(表示並且控制瀏覽器目前的位置)
在document也有一個location,照例,兩者並不等同,一般而言兩者會顯示同樣的值,但location物件的值可以被改變,而在document的location屬性值無法被改變.

1.用法,
location
window.location

2.一些常見的屬性


location物件常見的屬性
屬性表示
href是個字串,location儲存了目前視窗所顯示文件的URL完整文字內容
protocol通訊協定的類型
hostname網站的名稱,通常是網站首頁的路徑
host網站首頁的路徑,含port號
portport號
pathname目前的文件(網頁)在網站中的路徑
search查詢的部分包含前導的問號?
hash錨點的部分,包含前導的#號





location物件常見的方法
方法表示
replace()重置,可以指定任可一個新URL,替換掉href中的URL(感覺這個速度比較快)
assign()指定,同上
reload()重載,同上



♨1.所以,目前的文件(網頁)的完整路徑(href)其實就是:protocol.hostname(|host)(.port).pathname(.search)(.hash)(不過少了兩個正斜線)
♨2.讀取location的值,就是讀取location中href的值,我們也可以指定任何一個新的,聽說是因為location本身帶有自用的toString().
♨3.我們也可以指定任何一個新的路徑給視窗的location,則指定路徑的內容會被載入目前的視窗.而replace(),assign(),reload()也都可以造成同樣的效果.
所以若有不打算開放的網頁,都可以用location導回到首頁.
不過一般是用navigator在判斷使用者的瀏覽器是否太舊,若太舊而不支援Dhtml,就可以導向另一份單純的html網頁.
比較超連結物件




五.document物件
window的document屬性指向一個document物件,代表在視窗中所顯示的html文件.
一般來說,html文件中的每個元素(標籤)都會對應一個document物件中的屬性,如:html文件中的每個<form>標籤都會在document物件forms[]陣列中建立一個巳編號元素,每建立一個<img>標籤就會在document物件images[]陣列中建立一個巳編號元素,<a>標籤對應到links[],<applet>標籤對應到applet[].如form,img,applet元素中若有設定name屬性,在js中就可以用名稱指向該物件.
若<form name="f1"></form>是文件中的第一個元素.則以下所指的是同樣的事.
document.form[0]
document.f1
document.form.f1
document.form["f1"]


2.一些常見的屬性
document物件繼承了HTMLElement介面的所有屬性,此外還定義了下列屬性


document物件常見的屬性
屬性類型表示備註
body指向html中的body元素,即<body>
*domain物件代表網域
*URL物件代表文件的URL,屬性值是個字串,除非有重新導向,否則屬性值與window.location.href的值相同
*location物件與URL相同,代表文件的URL
*referrer物件連結到目前文件的文件的連結(若有的話)
*title物件代表文件的抬頭(<title>)
*cookie物件代表cookie
*images[]陣列代表圖片(<img>)來自HTMLElement
*embeds[]陣列
*anchors[]陣列文件中的錨點來自HTMLElement
*applets[]陣列文件中的Java applet
*forms[]陣列代表表單(<form>)來自HTMLElement
*lastModified物件代表文件(網頁)的最後修改日期,是個字串.
*links[]陣列代表文件中的超連結來自HTMLElement
*linkColor物件未訪問的連結顏色
*alinkColor物件訪問(點擊)時的連結顏色
*vlinkColor物件訪問過的連結顏色
*bgColor物件背景色
*fgColor物件前景色(文字的顏色)
doctype
dir
ownerDocument
*plugins

*activeElement唯讀屬性,指文件中目前活動的輸入元素(即具有輸入焦點的元素)IE
*all[]陣列文件中所有元素的陣列來自HTMLElement
*children[]陣列文件中所有直系子元素的陣列,以其在原始碼中的順序存放來自HTMLElement
*charset字集
*defaultCharset預設字集
*parentWindow包含文件的視窗
*readyState文件的載入狀態,有以下四個值可用,1.uninitialized:尚未開始載入2.loading:正在載入3.interactive:載入的文件巳足以與使用者互動4.complete:文件載入完畢
expando只在IE4有效

width文件的寬度Netscape
height文件的高度
layers[]陣列文件中所包含的圖層Netscape6巳廢除

nodeName節點名稱DOM
nodeType節點型態,傳回某節點類型
nodeValue
parentNode父節點,節點.parentNode則指向該節點的父節點
childNodes[]子節點群,此屬性會傳回該節點的子節點清單,節點.childNodes
firstChild指某一節點的第一個小節點
lastChild指某一節點的最後一個小節點
nextSibling指某一節點的下一個兄弟節點
previousSibling指某一節點的上一個兄弟節點
implementation

documentElement

attributes[]

styleSheets
compatMode





document物件常見的方法
方法內容備註
*write("字串")輸出,把字串書寫到目前的文件
*writeln("字串")段行輸出,把字串書寫到目前的文件,有換行功能(有附帶一個換行符號)
*open()開啟新文件
*close()關閉文件

*getSelection()傳回目前選取的文件文字Netscape
*elementFromPoint()傳回位於指定點(x,y)的元素IE
compareDocumentPosition()待查?
lookupPrefix()待查?
isDefaultNamespace()待查?
lookupNamespaceURI()待查?
getFeature()待查?
setUserData()待查?
getUserData()待查?

appendChild(節點)添加子節點DOM
removeChild(節點)移除子節點
replaceChild(節點1,節點2)重置子節點,用節點1取代節點2.
insertBefore()在文件樹中插入一個節點,插入到目前節點的指定子節點之前,
hasChildNodes()若目前節點具有子節點,就傳回true
cloneNode()複製目前節點,或複製目前節點及其所有子孫節點
*createTextNode()開一個文字節點
*importNode()對於其他適合插入此文件的文件,生它的節點副本
getAttributeNode()以Attr節點的形式,取得指定的屬性值
setAttributeNode()將指定的Attr節點加到元素的屬性列表中
removeAttributeNode()從元素的屬性中列表中刪除指定的Attr節點

*createElement("標籤名")用指定的標籤名稱,創建一個元素(創造出來的是個節點)
*createElementNS()用指定的標籤名稱和名稱空間新建一個元素節點
*createDocumentFragment()建立新的,空的DocumentFragment節點
*createComment()建立包含指定字串的新Comment節點
*createCDATASection()新建一個包含指定文字的CDATASection節點
*createProcessingInstruction()以指定標籤和貟料串新建一個ProcessingInstruction節點
*createEntityReference()新建EntityReference節點
指向具有指定名稱的實體,若此的DocumentType物件定義具有此名稱的Entity物件,則新建的EntityReference節點將具有與Enity相同的唯讀字串

*getElementsByTagName("標籤名")[n]依指定標籤名稱(元素)取得某特定標籤,會傳回一陣列,裡頭載有該文件裡我們所指定名稱的所有元素,所以要指定序號.
*getElementsByTagNameNS()取得指定標籤名稱和名稱空間的元素節點
*createEvent()以指定的型態新建一Event物件.
從技術上而言,此方法是由DocumentEvent介面定義的,只有在支援Events模組的實作中,Document物件才實作此方法

*createRange()新建一個Range物件.
從技術上來說,此方法是由DocumentRange介面定義的,只有支援Range模組的實作中,Document物件才能定義此方法

*createNodeIterator()新建NodeIterator物件.
從技術上而言,此方法是DocumentTraversal介面的一部分,只有在支援Traversal模組的實作中,Document物件才實作此方法

*createTreeWalker()新建TreeWalker物件.
從技術上來說,此方法是DocumentTraversal介面的一部分,只有在支援Traversal模組的實作中,Document物件才定義此方法


*getElementById("id名")依指定id名稱取得某特定標籤,
會傳回指定ID屬性的子孫元素節點,若没有這樣的元素節點就傳回null

removeEventListener()從節點的傾聽器集合中刪除一個事件傾聽器

hasAttributes()若目前節點是Element節點,而且具有HTML屬性,則傳回true
hasAttributeNS()
*createAttribute()以指定的名稱新建一個Attr節點
*createAttributeNS()以指定的名稱或名稱或名稱空間新建一個Attr節點
getAttribute()取得指定的屬性值字串
getAttributeNS()
setAttribute()設定指定的屬性值
setAttributeNS()
removeAttribute()從元素中刪除特定的屬性和屬性值
removeAttributeNS()
normalize()合併相鄰的Text節點並刪除空的Text節點
isSupported()判斷目前節點否支援某個HTML屬性
dispatchEvent()分派合成事件到此節點
*getOverrideStyle()取得指定元素(或非必要的指定虛元素)的CSS改寫樣式資訊.
從技術上來說,此方法是屬性DocumentCSS介面,只有在支援CSS模組的實作中,Document物件才實作此方法

isSameNode()待查?
isEqualNode()待查?
getAnonymousNodes()待查?Netscape
getAnonymousElementByAttribute()待查?Netscape

*captureEvents()請求指定型態的事件Netscape
*releaseEvents()停止捕捉指定型態的事件
*routeEvent()將捕捉到的事件分配到下一個指定的元素


adoptNode()待查?
clear()待查?
execCommand()待查?
execCommandShowHelp()待查?
queryCommandEnabled()待查?
queryCommandIndeterm()待查?
queryCommandState()待查?
queryCommandSupported()待查?
queryCommandText()待查?
queryCommandValue()待查?
getBoxObjectFor()待查?
setBoxObjectFor()待查?
addBinding()待查?
removeBinding()待查?
getBindingParent()待查?
loadBindingDocument()待查?





document物件常見的事件處理器
onbeforeeditfocus oncontextmenu onrowexit onactivate
onmousemoveonselectstartoncontrolselectonkeypress
onrowenter onmousedown onreadystatechange onbeforedeactivate
onmouseover onafterupdate ondragstart ondatasetcomplete
onmousewheel onerrorupdate onselectionchange ondblclick
onkeyup onrowsinserted onmouseup onkeydown
onrowsdelete onfocusout ondatasetchanged onmouseout
onpropertychange onstop onhelp onbeforeactivate
onbeforeupdate onclick onfocusin ondataavailable
ondeactivate


3.document物件的成員介紹

()Anchors,錨點物件
a.用法,document.anchors[i]
b.常見的屬性和方法
繼承自HTMLElement的屬性,至少還定義或改寫了以下的屬性

屬性表示備註
name錨點的名稱,<a>的name
trxt指錨點<a>和</a>之間的純文字.
只有<a>和</a>之間没有其他html標籤,此屬性才能完全運作



♨註,String物件中有個anchor(anchor-name)方法,string.anchor()=<a name="anchor-name">string</a>

()Link,超連結物件
a.用法,
document.links[]
document.links.length
b.常見的屬性和方法
繼承自HTMLElement的屬性,至少還定義或改寫了以下的屬性(length是繼承自陣列物件的)
以以下假設的URL為例
http://beba-brook.blogspot.com:1234/2006/06/javascript.html?q=JavaScript&m=10#results


屬性表示備註
href可讀寫字串,指完整的URL
protocol可讀寫字串,指URL的通訊協定片段,包含冒號http:
hostname可讀寫字串,指URL的主機名稱片段beba-brook.blogspot.com
host可讀寫字串,指URL的主機名稱和連接埠片段beba-brook.blogspot.com:1234
port可讀寫字串,指URL的連接埠片段1234
pathname可讀寫字串,指URL的路徑片段/2006/06/javascript.html
search可讀寫字串,指URL的查詢片段,包含前導的問號?q=JavaScript&m=10
hash可讀寫字串,指URL的錨點的片段,包含#號#results
target可讀寫字串,指開啟連結文件的window物件名稱(框架或視窗名)
text可讀寫字串,指<a>和</a>之間的純文字Netscpae特有,相當於IE的HTMLElement.innerText
onclick當連結被點擊時事件處理器
onmouseout當滑鼠離開時事件處理器
onmouseover當滑鼠移過時事件處理器



♨註,
(1)String物件中有個link(url)方法,string.link(url)=<a href="url">string</a>
(2)Link物件和location物件的屬性一模一樣,
location物件代表目前視窗所顯示文件的URL,所以location物件的屬性不知是不是繼承自Link.
不過location和document是同一層的,Link物件是document物件的成員,參location物件


()Applets
a.用法,
document.applets[i]
document.appletName
b.常見的屬性和方法
Applets物件的屬性和方法,和它所代表的Java applet的公開欄位或方法相同


屬性等表示備註




4.document物件中,與表單相關的物件

(1)Form,表單物件
就是<form>
a.用法,
document.form_name
document.forms[i]

b.常見的屬性和方法
繼承自HTMLElement的屬性,至少還定義或改寫了以下的屬性


屬性等表示備註
action可讀寫字串,<form>的action屬性,值是URL屬性
elements[]一個陣列,陣列元素是表單中的輸入元素,如Button,Checkbox,Radio,Text等
encoding可讀寫字串,<form>的enctype屬性
length可讀寫字串,表單中的元素個數,即elements.length
method可讀寫字串,<form>的method屬性,值是get或post
name可讀寫字串,,<form>的name屬性
target可讀寫字串,,<form>的target屬性,值是window_name
reset()重設表單方法
submit()送出表單
onreset()重設表單時呼叫事件處理器
onsubmit()送出表單時呼叫



(2)Input,表單的輸入物件
就是<form></form>之間的<input>

a.用法,
form.elements[i]
form.name
b.常見的屬性和方法
繼承自HTMLElement的屬性,至少還定義或改寫了以下的屬性

屬性等表示備註
defaultChacked唯讀的布林值,即<input>的checked屬性,若checked有被設定,defaultChacked的值就是true屬性
defaultValue指該表單元素出現的初始文字,也能在重設表單時可以使用此值來恢復元素,只有Text,Password,Textarea元素使用這個屬性,對Checkbox,Radio來說,與之等同的屬性是defaultChecked,FileUpload基於安全考量就没有defaultValue
form唯讀,指向含有該元素的Form物件,使用form屬性,表單元素的事件處理器就能輕易地指向與它處於同一表單中的兄弟元素,在呼叫事件處理器時,關鍵字this可以指向呼叫該處理程式的表單元素,因此,事件處理器可以使用運算式this.form來指向含有該兀素的Form物件,從而就可以使用名稱或者使用Form物件的elements[]陣列中的索引值來指向該元素的兄弟元素
length對於Select表單元素,此屬性指向options[]陣列中存放的選項數
name唯讀的字串,由html的標籤屬性name設定(即指定了元素的名稱,為該元素命名),此名稱可用來指向該元素
option[]對Select來說,這個陣列存放的是Option物件
selectedIndex對Select來說,這個整數指目前選取的Select物件的選項
type唯讀字串,指定表單元素的型態,即<input>的type屬性
value字串,指表單元素顯示的值,或在送出表單時,該元素要傳送出去的值,即<input>的value屬性
blur()將鍵盤焦點從元素中移開方法
click()在表單元素上模擬滑鼠點擊
focus()將元素上設置鍵盤焦點
select()對於顯示可編輯文字的單元素來說,選取其中的所有文字
onblur當使用者把鍵盤焦點從元素中移開時呼叫事件處理器
onchange對非按鈕的表單元素來說,當使用者輸入或選擇新值時呼叫
onclick對按鈕類的表單元素來說,當使用者點擊或選擇該按鈕時呼叫
onfocus當使用者將鍵盤焦點對到該元素時呼叫



(3)Text,文字框物件
就是<input>中屬性type的text值
a.用法,
form.name
form.elements[i]
b.常見的屬性和方法
繼承自Input物件和HTMLElement的屬性,至少還定義或改寫了以下的屬性


屬性等表示備註
value可讀寫字串,就是<input>中屬性value的值(預設出現在文字框中的文字)屬性
onchange若Text元素中的值被改變,並且將呼叫焦點移到別處時呼叫事件處理器


c.屬性的用法
#Text.onchange
<input type="text" onchange="handler"... value="在這裡輸入文字">
text.onchange

(4)Password,密碼框物件
就是<input>中屬性type的password值

a.用法,
form.name
form.elements[i]

b.常見的屬性和方法
繼承自Input物件和HTMLElement的屬性,至少還定義或改寫了以下的屬性


屬性等表示備註
value可讀寫字串,就是<input>中屬性value的值屬性



(5)Checkbox,核取方塊物件
就是<input>中屬性type的Checkbox值

a.用法,
form.checkbox_name
form.elements[i]
若表單含有一組具相同名稱的核取方塊,則其存放在同一個陣列中
form.checkbox_name[j]
form.checkbox_name.length

b.常見的屬性和方法
繼承自Input物件和HTMLElement的屬性,至少還定義或改寫了以下的屬性

屬性等表示備註
checked可讀寫的布林值,若選取了該核取方塊,checked屬性為true屬性
defaultChecked唯讀的布林值,指核取方塊的預設狀態,
value<input>的value屬性,指送出表單時,若該核取方塊被選取應該傳給伺服端的文字
onclick按鈕被點擊事件處理器

c.屬性的用法
#Button.onclick
<input type="checkbox" onclick="handler">
checkbox.onclick

(6)Radio,單選鈕物件
就是<input>中屬性type的radio值

a.用法,
form.radio_name[i]
form.radio_name.length

b.常見的屬性和方法
繼承自Input物件和HTMLElement的屬性,至少還定義或改寫了以下的屬性


屬性等表示備註
checked可讀寫的布林值,若單選鈕被選取,checked屬性的值就是true屬性
defaultChecked布林值,<input>中有使用checked屬性時,若在單選鈕的初始情況處選取狀態,defaultChecked值就是true
value可讀寫的字串,就是<input>中屬性value的值
onclick單選鈕被點擊時事件處理器



(7)Reset,重設鈕物件
就是<input>中屬性type的reset值
a.用法,
form.name
formelements[i]

b.常見的屬性和方法
繼承自Input物件和HTMLElement的屬性,至少還定義或改寫了以下的屬性

屬性等表示備註
value字串,就是<input>中屬性value的值屬性
onclick單選鈕被點擊時事件處理器

c.屬性的用法
#reset.onclick,
<input type="reset" value="重設" onclick="handler">
reset.onclick

(8)Submit,確認鈕物件
a.用法,
form.name
form.elements[i]
form.elements['name']

b.常見的屬性和方法
繼承自Input物件和HTMLElement的屬性,至少還定義或改寫了以下的屬性

屬性等表示備註
value字串,就是<input>中屬性value的值屬性
onclick當確認鈕被點擊時呼叫事件處理器


c.屬性的用法
#submit.onclick,
<input type="submit" value="確定送出" onclick="handler">
submit.onclick

屬性等表示備註




(9)Button,按鈕物件
就是<input>中屬性type的button值
a.用法,
form.button
form.elements[i]

b.常見的屬性和方法
繼承自Input物件和HTMLElement的屬性,至少還定義或改寫了以下的屬性

屬性等表示備註
value<input>的value屬性,是唯讀的屬性
onclick按鈕被點擊事件處理器

c.屬性的用法
#Button.onclick,
<input type="button" value="按我" onclick="handler">
button.onclick

(10)FileUpload
就是<input>中,屬性type的屬性值file,表單輸入元素中的檔案上載欄位

a.用法,
form.name
form.elements[i]

b.常見的屬性和方法
FileUpload物件繼承了Input物件和HTMLElement物件的屬性和方法,還定義或改寫了以下屬性

屬性等表示備註
value唯讀字串,指使用者在FileUpload物件中中輸入的檔案名稱屬性
onChange當使用者改變FileUpload元素的值,且將鍵盤焦點移到別處時呼叫事件處理器

c.屬性的用法
#FileUpload.onChange
<input type="file" onChange="handler">
checkbox.onChange

(11)Select,下拉選單物件
就是<select>
a.用法,
form.element_name
form.elements[i]
b.常見的屬性和方法
繼承自Input物件和HTMLElement的屬性,至少還定義或改寫了以下的屬性


屬性等表示備註
selectedIndex一個整數,指Select物件中被選取的選項索引,若沒有選取任何選項該屬性值為-1屬性
option[]Option物件的陣列,其中每個元素描述Select元素中顯示的選項
type唯讀字串,由有的表單元素共用,指元素的型態,
length唯讀整數,指option[]陣列中的元素個數,屬性值於options.length的屬性值相同
onchange()當一個選項被選取或取消選取時呼叫事件處理器



#select.selectedIndex,若選取多個選項,它的只是第一個選項的索引.
在JS1.0中selectedIndex屬性是唯讀的,在JS1.1時可以讀寫,可以透過設定它而選取某特定的選項,還可以取消對所有選項的選取,在使用multiple屬性的情況下,可以將selectedIndex設為-1,而取消對所有選項的選取.

#select.option[]
option[]存放一個Option物件的陣列,其中每個元素描述Select物件select中的一個選項,option.length指讓陣列中的元素個素,與select.length相同.

a.用法,
select.options[i]
select.options.length


#select.type,在Select物件中有兩種可能的type值,若没有設定multiple屬性(就是單選),則type屬性值是“select-one”,若設定multiple屬性(就是多選),則type屬性的值就是“select-multiple”.

(12)Option,下拉選單的選項物件
就是<select>中的<option>
a.用法,select.options[i]

b.建構式
在JS1.1中,可以使用Option()建構式建立Option物件
new Option("text","value","defaultSelected","selected")

c.常見的屬性和方法
繼承自Input物件和HTMLElement的屬性,至少還定義或改寫了以下的屬性


屬性等表示備註
text可讀寫字串,指顯示給使用者的選項文字,屬性值就是出現在<option>後面(,或說在</option>或<select>前面)的文字屬性
value可讀寫字串,就是<select>中的<option>的value屬性值
defaultSelected布林值,指在建立包含該屬性的Select物件時,該選項是否被選取,就是<select>中的<option>的selected屬性值所設定的值
selected可讀寫字串,指一個選項目前是否選取,可檢測某選項是否被選取,也可以選取或取消一個選項
index唯讀的整數,指選項在包含它的Selet物件的options[]陣列中的索引位置



(13)Textarea,文字區塊物件
就是<textarea>
a.用法,
form.name
form.elements[i]
c.常見的屬性和方法
繼承自Input物件和HTMLElement的屬性,至少還定義或改寫了以下的屬性

屬性等表示備註
value可讀寫的字串,其初始值與屬性defaultValue的值相同,就是在<textarea>和</textarea>之間的文字屬性
onchange當使用者改變Textarea元素中的值,並且將鍵盤焦點移到別處時呼叫事件處理器


c.屬性的方法
#textarea.onchange
<textarea>
textarea.onchange


物件標籤type屬性
Text<input type="text">button
Password<input type="Password">password
Button<input type="Button">button
Checkbox<input type="Checkbox">checkbox
Radio<input type="Radio">radio
Reset<input type="Rest">reset
Submit<input type="Submit">submit
Select<select>select-one
Select<select multiple>select-multiple
Textarea<textarea>textarea



屬性等表示備註




第十章 DOM;文件物件模型(document object model;DOM)

零.w3c的DOM
將html中的階層,化成樹狀圖,html中的每個元素和元素的內容都是樹狀圖中的節點

1.html文件的樹狀結構
<html>
<head>
<title>DOM的樹狀圖</title>
</head>
<body>
<h1>DOM的樹狀圖示例</h1>
<p>這就是<i>DOM樹狀圖</i>示例
</body>
</html>

節點上面的節點,就是該節點的父節點.節點下一層的節點,就是該節點的子節點.位在同一層的節點若有相同的父節點,就是兄弟節點(sibling).
某節點下面的所有節點都是該節點的子孫節點.某節點上方的所有節點都是該節點的祖先節點.

一.節點(node)

1.DOM結構樹是由各式各樣的節點(node)物件所組成的一棵樹。
結構樹根部的document物件,就是個節點(node)物件.
node介面定義了查尋樹結構,以及處理樹結構(就是節點)的屬性和方法.
♨DOM規範定義的是介面,不是類別.在OOP(物件導向程式設計)中的一種另類東東,可以簡單想成是類別的抽象形式
如:childNodes屬性會傳回傳回某節點的子節點清單.
firstChild、lastChild、nextSibling、previousSibling、parentNode等屬性,是用來查尋DOM文件樹中的節點的手段.
appendChild()、removeChild()、replaceChild()、insertBefore()等方法可以用來在文件樹中新增和移除節點.

2.節點的型態
文件樹中的各式各樣節點都是由node這個介面的子介面來表達.由上圖例表達可以知道,節點並不限於html的元素.也有可能是文字或文件.
而每個node物件都會有一個nodeType屬性,用來判別某節點的型態.
如html而言,若某一節點是個元素(element),則nodeType的屬性值就會傳回一個常數Node.ELEMENT_NODE(符號常數).所以我們就可以知道這個node物件也是個element物件.則我們就可以用element介面所有的屬性和方法來處理這個節點.
其他如DOM文件樹中的根節點document物件中就有個documentElement屬性.它會指向代表該文件的Element物件,對於html文件而言,就是<html>標籤.(根元素)



常見的nodeType屬性傳回的節點型態常數值
介面nodeType常數表示傳回值
ElementNode.ELEMENT_NODE元素1
TextNode.TEXT_NODE文字3
DocumentNode.DOCUMENT_NODE文件9
CommentNode.COMMENT_NODE註解8
DocumentFragmentNode.DOCUMENT_FRAGMENT_NODE
AttrNode.ATTRIBUTE_NODE


♨但調nodeType出來,往往是數值型態的整數常數.



二.元素

2.html標籤屬性(Attribute)

DOM的威力並不限於html,甚至xml,CSS都是.但html是網路最通用的文件,所以對於html著重多一些也不過份.
node介面規範所有的節點,element介面規範了所有的元素,至於html元素中的屬性(Attribute),element介面也提供了一些方法供我們存取及刪除,如getAttribute()、setAttribute、removeAttribute。
或用getAttributeNode(),它會傳回一個Attr物件,載有html標籤的屬性及屬性值.(聽說這種方法比較麻煩,但是有個好處,Attr介面定義了個specified屬性,可以讓我們知道標籤屬性是直接寫在文件裡,或者該屬性其實是個預設值.)
♨聽說Attr介面(Attribute?)是節點的一種,但Attr物件並不會出現在childNodes[]子節點清點中,所以它跟其它節點不一樣,並非直接屬於文件的一部分.基本上呢,在DOM規範裡Attr節點可以經由node介面的Attribute[]存取,不過聽說IE又跟人家不一樣了,IE定義了不相容的Attribute[],所以這個方法無法跨平台

三.DOM中的專屬html的介面

1.DOM標準設計如node(節點)、element(元素)、document(文件)等等核心介面的API(application programming interface;應用程式介面),概括性十足,所以不限於html也適用於XML.
DOM標準也專門替html文件設計了專屬的介面(因為就目前來說,html仍是網路最通用的文件).
如document介面下的子介面HTMLdocument就可視作專屬於html的子介面
在元素方面DOM標準也替很多html元素設計了專用的介面.通常這些介面都會有一組屬性對應到html標籤的屬性.
♨在w3C標準的DOM設計出爐之前,HTMLdocument裡頭就巳經定義了一些屬性和方法了,如location,forms[],write()等等,都是在w3C的DOM標準之前,瀏覽器就巳支援的東東了.

2.HTMLdocument介面定義了id、classname、style、title、lang、dir屬性.這些屬性可以讓我們存取部分html標籤中的id、class、style、title、lang、dir屬性.
如<big>、<cite>、<center>、<em>、<i>、<u>、等等,這些元素除了上述的6個屬性外再也没有其他屬性,所以這些標籤都是由HTMLdocument來表達.

3.其他的html標籤在DOM中都有相對應的介面.對絕大部分的html標籤而言,這些相對應的介面只是提供了一組屬性,對應到html標籤的屬性.
如<body>就對應到HTMLBodyElement,<ul>就對應到HTMLUListElement,這些介面都定義htlm規範定義的標籤屬性.
so,一般而言,我們可以大胆的認定,代表某一個html標籤HTMLElement物件會擁有一組屬性,對應到該標籤的標準屬性.

不過,一般來說,要存取html標籤屬性還是會用,上述element介面的getAttribute()、setAttribute、removeAttribute()等方法.

4.DOM的專屬html介面的命名習慣.
(1)開頭一定是“HTML”,結尾通常是“Element”,中間通常是html元素的名稱.
如<imput>就是HTMLImputElement,上述舉過的HTMLBodyElement就是<body>HTMLUListElement就是<ul>
<imput>裡的屬性maxLenght就是HTMLImputElement介面的maxLenght屬性.

(2)html標籤屬性的名稱和JS的關鍵字衝突時,就在前面加一個“html”來避開衝突.
如<label>的for屬性,在HTMLLableElement介面中的屬性就是htmlfor.
元素的命名在上述(1)規則中大致没有什麼問題,html標籤的屬性名稱,少數有衝突的就加“html”,一般來說html標籤的屬性名稱,就是所對應的DOM介面裡的屬性名稱.

唯一的例外就是class,它對應到HTMLdocument介面的classname
(其實也不算例外,因為它是傳統HTMLdocument介面下的,不是新一波W3C的DOM標準規範下的,但適用於任何元素.)

5.
聽說DOM有兩種,DOMLevel 1主要定義了DOM核心,如Node、Element、Attr、Eocument、Text
到了DOMLevel 2聽說巳經模組化了,除了Level 1的核心模組外,還擴及CSS和事件(Events)模組.
核心模組是唯一必要的模組,其他的模組都是選用的.實作DOM的軟體如瀏覽器除了實作核心模組,必然也會支援HTML模組(因為瀏覽器是上網用的嘛,而網路目前最通行的文件還是html),而哪一個瀏覽器是否支援其他非必要的模組?支援哪些模組?這些細節聽說是程式設計員自己要去暸解的.
目前DOM的規範標準巳訂到Level 3了.
想知道某個瀏覽器支援細節,w3c有網路線上測試可以用
http://www.w3c.org/DOM/Test/


Level 1:核心介面、HTML介面、XML介面.
Level 2:core(核心)介面、HTML介面、XML介面、Views(AbstractView介面)、CSS、Events、UlEvents(使用者事件)、MouseEvents、HTMLEvents、MutationEvents(文件變更事件)、Range(文件範圍介面)、Traversal(文件尋訪介面).

四.尋訪文件

常用的有node介面的:childNodes,firstChild,lastChild,nextSibling,previousSibling

1.利用childNodes屬性徧歷節點,查節點數量.

(1)以下是個標準的遞迴函數,可以利用childNodes求得文件中節點的數量.
(既然這麼經典,又被布魯克看到,所就放上來了)

function countTags(n){ //接收node物件
var numtags=0; //標籤計數,預設0
if(n.nodeType==1){ //判斷是節點是否是元素(nodeType=1),若是標籤計數器加1.
numtags++;
}
var children=n.childNodes; //擷取子節單清單.
for(var i=0;i< children.length;i++){//如若傳入document則,document.children.length=2
numtags+=countTags(children[i]);
}
return numtags;
}

document.write('這份文件共有:'+countTags(document)+'個標籤');//呼叫countTags涵數

(2)這個涵數和上方那個是一樣的
var sumtags=0; //標籤計數,預設0
function countTags(n){ //接收node物件
if(n.nodeType==1){ //判斷是節點是否是標籤(nodeType=1),若是標籤計數器加1.
sumtags++;
}
var children=n.childNodes; //擷取子節單清單.
for(var i=0;i< children.length;i++){
countTags(children[i]);
}

}

countTags(document); //呼叫countTags涵數
document.write('這份文件共有:'+sumtags+'個標籤');

(3)如在一空白的html文件下如下,用這個涵數會出標籤數量是5個.就是<html>,<head>,<title>,<body>,<script>
放入的若是body標籤(document.body),顯示的標籤數量是2個.就是<body>,<script>

<html>
<head>
<title></title>
</head>
<body>
<script>
JS程式碼...
</script>
</body>
</html>

(4)childNodes[]的儲存方式

所以由上述的涵數可知,childNodes這個東東,應該是長這樣的


childNodes陣列的儲存長相
調動的childNodes陣列顯示
document.childNodes[0]DocumentType
document.childNodes[1]HTMLHtmlElement
document.childNodes[3]undefined
document.childNodes[0].childNodes[0]undefined
document.childNodes[0].childNodes[1]undefined
document.childNodes[1].childNodes[0]HTMLHeadElement
document.childNodes[1].childNodes[1]HTMLBodyElement
document.childNodes[1].childNodes[2]undefined
document.childNodes[1].childNodes[0].childNodes[0]HTMLTitleElement
document.childNodes[1].childNodes[0].childNodes[1]undefined
document.childNodes[1].childNodes[1].childNodes[0]HTMLScriptElement
document.childNodes[1].childNodes[1].childNodes[1]Text
document.childNodes[1].childNodes[1].childNodes[2]undefined


document這個物件下方有兩個節點,一個是Document,一個是html
childNodes[0]是文件型態,childNodes[1]是html標籤,
childNodes[2]及以後,裡頭没東西(所以才可以知道document這個物件下方只有兩個節點.)
childNodes[0,0],childNodes[0,1]及以後,因為childNodes[0]下方没有節點了,所以裡頭没有東西.

html這個節點(childNodes[1])下方又有兩個節點:
childNodes[1,0]是head標籤,childNodes[1,1]是body標籤.
childNodes[1,2]含以後,就没節點了.

head這個節點(childNodes[1,0])下方有一個節點:
childNodes[1,0,0]是title標籤
childNodes[1,0,1]含以後,就没節點了.

body這個節點(childNodes[1,1])下方有兩個節點:
childNodes[1,1,0]是script標籤
childNodes[1,1,1]裡頭是文字(可能是空白造成的,也有可能出現更多的文字節點,否則理論上應該只有一個節點.)
childNodes[1,1,3]含以後,就没節點了.

所以childNodes[]儲存節點的方式,應該是滿傳統的.就是用一個陣列去儲存一層節點.
該節點下方還有節點就開一個陣列去儲存,一真反複下去,造成二維,三維...等陣列.
應該還算滿合理的,除此之外布魯克還真想不出還能有什麼方式去儲存這些節點.

2.利用firstChild和nextSibling屬性徧歷節點,取得文件中的字數
(1)以下是個標準的遞迴函數,可以利用firstChild和nextSibling求得文件中字元的數量.
(既然這麼經典,又剛好被布魯克看到,所又放上來了)

function countChar(n){ //接收節點物件
if(n.nodeType==3) return n.length; //徧歷陣列,若物件節點型態是文字,傳回字元長度
var numchars=0; //字元儲存器預設是0
for(var m=n.firstChild;m!=null;m=m.nextSibling){
//取得該節點的子節點,若子節點非空,把該節點再帶入函數取得字元長度並加總.再前往下一個節點
numchars+=countChar(m);
}
return numchars;
}
document.write("≶br>這份文件的共有"+countChar(document.body)+"個字");

♨但這個涵數測出來的字數是不準的,如
在ie來說:若有html註解,每個註解都會被視為一個字.
firefox若遇到html註解,就不會把註解計算進去字數裡,不過它若遇到script的程式碼,會將script程式碼的字數包含script的註解都計算進去,這點ie是不會的.
但不論是ie或firefox遇到空白,都會視為一個字元,所以無論如何,字數都是不準的


五.找出文件中的特定元素
我們也能在文件中找出特定的標籤
常用的方法有:getElementsByTagName(),getElementById()

(1).getElementsByTagName()
1.getElementsByTagName()能依指定的標籤名稱(元素)取得特定標籤.如一般若原先在document中有定義的屬性如:body,title,images,forms.直接指用document取得該屬性,就能指向該標籤了.如要指向一份文件的body標籤,document.body就可以了.指向title也一樣.
但呼叫getElementsByTagName(),指定document.getElementsByTagName("body")[0].也能指向<body>.
getElementsByTagName()會傳回指定標籤的陣列,像<p>或<table>等就會有很多個.它會依其在文章中出現的順序依次傳回.而body;title這種標籤,照理說它也會傳回文件中所有的body或title,但因為一份html文件只有一個body和title,所以傳回的陣列裡的第一個元素[0],就是我們要的body或title.
總之,我們可以用getElementsByTagName()取得文件中任何我們要的元素.
如var table=document.getElementsByTagName("table");
document.write("這份文件中共有"+table.length+"張表格.");
♨因為html不分大小寫,所我們只要document.getElementsByTagName("body");,不論是<table>或<TABLE>都會被找到並傳回來.

如上例:


2.我們也可以傳送號「*」給getElementsByTagName(),即document.getElementsByTagName(*),則會傳回所有的元素.跟用document.all是一樣的
♨在IE6之前,並不支援這種用法,IE要取得所有的元素有IE專用的document屬性叫作all.
經測試在IE6document.getElementsByTagName(*)也可以用.
而all原本雖是IE特有的,但firefox目前也支援了(v2.0.0.11).


3.將上方找出節點數量的涵數,再加上getElementsByTagName()方法包裏起來的涵數,則可以顯示節點數量,和秀出節點清單.

function showTags(m){ //接收node物件
var sumtags=0; //標籤計數,預設0
function countTags(n){ //接收node物件
if(n.nodeType==1){ //判斷是節點是否是標籤(nodeType=1),若是標籤計數器加1.
sumtags++;
}
var children=n.childNodes; //擷取子節單清單.
for(var i=0;i< children.length;i++){
countTags(children[i]);
}

}

countTags(m); //呼叫countTags涵數
document.write('這份文件共有:'+sumtags+'個標籤
');

var alltags=document.getElementsByTagName("*");
for(k=1;k<=sumtags;k++){
document.write(k+alltags[k]);
//document.write(k+document.all[k]); //或用這段也可以
}
}
showTags(document);


(2)getElementById()

1.getElementsByTagName()可以取得我們指定的任意元素.不過還不夠精準.如上所述,元素在文件中若不是唯,一的,就會傳回一群.如<p><table>...等等.
要準確地取得某一指定的標籤,解決的方法是在標籤訂個屬性id,如此就可以使用getElementById()取得任可一個我們要的標籤.因為每個id的值都是獨一無二的.(我們自己訂的嘛,訂個獨一無二的名字就行了.)
所以呼叫getElementById()所傳回的值只會有一個,和getElementsByTagName()傳回一個陣列不同.
所以才叫:「getElementById()」和「getElementsByTagName()」.
(多了個s,因為getElementsByTagName()傳回的值不止一個嘛)

2.注意,不論是getElementsByTagName()或是getElementsById(),都是document物件的方法.
但,Element物件也有定義一個getElementsByTagName(),這個方法的作用範圍僅限於呼叫這個方法的元素之內,而非整份文件.
所以也可以見到這樣用的.
//找出某特定的表格,然後計算這個表格有幾列.
var table=document.getElementById("table0");//取得特定表格
var rows=table.getElementsByTagName("tr"); //取得表格中的所有列
var sumrows=rows.length; //取得列數
document.write("nodeType的列表共"+sumrows+"列");

布魯克在表格:nodeType屬性傳回的節點型態常數值列表中訂了個id叫table_nodeType,下面是傳回的列數:


在childNodes陣列的儲存長相列表中訂了個id叫:table_childNodes,下面是傳回的列數:



此外用class當然也可以才對,因為class的作用跟id一樣嘛,只是為了標示而巳.
上述的id、classname、style、title、lang、dir等屬性大部分的元素都會有應該都可以用類似的作用.
不過上巳述及,這些都是HTMLdocument介面定義的.所以...待查?
另document.documentElement和document.body中也有classname屬性.

六.創建及修改文件內容

常用方法:document.createElement():建立標籤(節點),
document.createTextNode():建立文字(節點),
節點.appendChild():添加子節點,
節點.removeChild():移除子節點,
節點.replaceChild():重置子節點,

(1)appendChild(節點),可以添加一個節點

1.利用appendChild()添加節點
function add(n){ //接收節點物件
var m=document.getElementById(n); //取得指定節點
var kids=m.childNodes; //取得子節點清單
n.appendChild(kids[0]); //添加第一個節點
}
<button onclick="add(節點);">添加</button>
//顯示



1.我...

2.我要...

3.我要你...

4.我要你滴...

5.我要你滴愛...




♨至於為什麼使用appendChild()會變成一直循環?布魯克也不清楚,聽說只要傳入appendChild()中的不是整份文件,而是文件的一部分,則它要添加時,會自動先做移除的動作,所以就變成移除了第一個節點,再把第一個節點添加在最後一個位置,就造成循環的現象,又因為是每次添加「一個」節點.所以是先移除添加標籤節點,再移除增加子節點所以會先跳一格(移除添加標籤節點)才會換文字.
2.聽說childNodes這個屬性是「動態的」,(又聽說DOM所有類似節點清單(NodeList)的介面都是這樣的).當文件修改過後,childNodes這個屬性會立刻反應出修改的結果,就是removeChild()後,會立即改變它後面兄弟節點的編號,總之因為這個關係,要用迴圈遍覽NodeList,又使用removeChild()要很注意.
布魯克也嚐試用表格來try但有問題,一定是哪邊作錯...待查.


1我...
2我要...
3我要你...
4我要你滴...
5我要你滴錢...
6你為什麼不拿出來?...




(2)removeChild(節點),可以移除一個節點

2.利用removeChild()移除節點
function dec(n){ //接收節點物件
var m=document.getElementById(n); //取得指定節點
var kids=m.childNodes; //取得子節點清單
n.removeChild(kids[0]); //添加第一個節點
}
<button onclick="dec(節點);">添加</button>

//顯示



1.我...

2.我要...

3.我要你...

4.我要你滴...

5.我要你滴愛...





3.利用appendChild(),removeChild(),將文件內容中的節點次序顛倒

//這個涵數可以將節點的次序顛倒過來
function reverse(n){ //接收節點物件
var kids=n.childNodes; //取得子節點清單
var numkids=kids.length; //取得子節點清單長度,找出有多少子節點
for(var i=numkids-1;i>=0;i--){//(反向)一一取出節點,為什麼要這麼做?
var c =n.removeChild(kids[i]);//因為要從最後一個開始取,依次移除一個子節點
n.appendChild(c); //將移除的子節點再添加到m
}
}
<button onclick="reverse(document.body);">按看看</button>

//顯示



1.我...

2.我要...

3.我要你...

4.我要你滴...

5.我要你滴愛...





如上述,只要傳入appendChild()中的不是整份文件,而是文件的一部分,則它要添加時,會自動先做移除的動作,所以上方的涵數不用removeChild()也可以造成同樣的效果.

function reverse(n){ //接收節點物件
var want=document.getElementById(n);
var kids=want.childNodes; //取得子節點清單
var numkids=kids.length; //取得子節點清單長度,找出有多少子節點
for(var i=numkids-1;i>=0;i--){//(反向)一一取出節點,為什麼要這麼做?
// var c =want.removeChild(kids[i]);//這段可以省略
want.appendChild(kids[i]); //改用這段就行了.
}
}

<button name="add" onclick="reverse('want');">倒置</button>
♨總之就是類似appendChild(),removeChild(),這種新增/修改文件內容的節點控制能力使得JS亮亮亮...亮起來(應該算在DOM頭上).如appendChild(),既然會循環,若設個timeout就可以拿來做跑馬燈了,文件收放隱藏等等,也能夠達成的

4.利用appendChild(),removeChild(),將文件內容中的節點次序顛倒的另一個範例.

//這個遞迴函數可以將節點和Text節點的字元次序顛倒過來
function reverse(m){ //接收節點物件
if(m.nodeType==3){ //若是文字節點
var texts=m.data; //*取得文字節點內容
var reversed="";
for(var i=texts.length-1;i>=0;i--){
reversed+=texts.charAt(i); //*依次取得字串中的字元
}
m.data=reversed; //重新存回逆轉後的文字
}else{

var kids=m.childNodes; //取得子節點清單
var numkids=kids.length; //取得子節點清單長度,找出有多少子節點
for(var i=numkids-1;i>=0;i--){ //(反向)一一取出節點
reverse(kids[i]);
m.appendChild(m.removeChild(kids[i]));//將移除的子節點再添加到n
}
}

}

<button onclick="reverse(document);">倒置</button>
♨這個涵數很神奇呀,傳送物件如document或document.body都没問題
傳送字串,再去涵數中取得指定字串的物件,它反而給我罷工了.不傳物件直接在函數中指定,它也不爽.


5.利用appendChild(),removeChild(),replaceChild(),createTextNode(),將文件內容換成大寫.

//這個遞迴函數可以將所有Text節點的字元換成大寫,(是用toUpperCase()當然是要英文字母才有用.)
function uppercase(n){
if(n.nodeType==3){ //若是文字節點
//*建立一個新文字節點,內容是原先文字節點內容的大寫
var newNode=document.createTextNode(n.data.toUpperCase());
var parent=n.parentNode; //為搜尋到的文字節點,建立一個父節點
parent.replaceChild(newNode,n); //*把新的文字節點替換原先的文字節點
}else{
var kids=n.childNodes; //取得子節點清單
for(var i=0;i<=kids.length;i++){ //遍覽子節點
uppercase(kids[i]);
}
}
}
<button onclick="uppercase(document.getElementById('toBig'));">大寫</button>



When I was young I'd listen to the radio.Waitin' for my fav'rite songsWhen they played I'd sing along

It made me smileThose were such happy times and not so long ago
How I wondered where they'd gone...♨這段有<br>
But they're back again ...♨這段有<br>
♨林老師...hoo lain to me,遇到<br>就行不通了,段落不行,連段行也不行.就算都不按enter,上方可見,作用也只及於第一個標籤,就是那個變粗體那行,第二個標籤以後,就是從變斜體那段以後,這個函數就通通没作用了,有誰寫文章都不用按enter的?
而且林老師又來了,取得物件再傳出去都没事,傳送字串在函數中取得指定字串的物件,或不傳物件直接在函數中指定,它又不爽了.我今天不知道是踩到哪隻蟑螂了.用個遞迴就溢出?


上述第3和第4個顛倒節點和文字次序的函數是用appendChild(),removeChild()改變子節點的次序,其實在DOM結構樹中的任何一個節點,都可以在DOM結構樹的範圍內移來移去(即必須在同一份文件中).
第5個將字元轉大寫的函數,是用createTextNode()建立一個新的文字節點,再找到傳入節點的父節點parentNode,用replaceChild()以新的文字節點替換原先的文字節點.
其實也可以用appendDate(),inserData(),deleteData(),replaceData()等方法直接在文字節點中,添加、插入、刪除、替換文字.這些方法是Text文字介面從CharacterDate字元資料介面中繼承下來的.

6.用createElement(),appendChild(),replaceChild()將文件內容換成粗體.
這個函數將原本的節點移到一個新建節點的下方.
即是用createElement()新建一個元素節點(標籤),用replaceChild()把原先的節點替換成新節點,再用appendChild把原先的節點添加在新節點下方.

//這個函數可以將一個指定的Text文字節點的內容變粗體
function embolden(node){
var bold=document.createElement("b");//建立個新元素<b>
var parent=node.parentNode; //取得傳入節點的父節點
parent.replaceChild(bold,node); //以新建的節點取代原先的文字節點
bold.appendChild(node); //在新建的節點下添加原先的文字節點
}

<button onclick="embolden(document.getElementById('toBold'));">變粗</button>



When I was young I'd listen to the radio.
Waitin' for my fav'rite songs.
When they played I'd sing along.
It made me smile.
Those were such happy times and not so long ago.

How I wondered where they'd gone.

But they're back again ...



七.Treewalker;Range介面
上述論及了DOM核心API,有一些基本的方法可以尋訪和處理文件
DOM也提供了其他選用的API模組.
其中有兩毎選用模組本質上是方便性的API,建立在核心API之上,
Traversal API定義了很方便的技巧,可以讓我們尋訪文件,把不用的節點過濾出來
Tange API定義了方法,可以處文件內的幾個連續範圍,即使內容的起點及終點不是在節點上也無所謂

1.Treewalker介面
由上述,我們巳經可以用遞迴節點的方式尋訪文件,這是佷重要的技巧,但通常比較費時,我們不需要檢視文件中的每個節點.
相反的,我們可能只想看文件中的<img>元素,或者尋訪<table>元素的子孫系.
Treewalker提供了高階的技巧讓我們做這種選擇性的文件尋訪,
因為Treewalker是選用介面,若我們想知道瀏覽器是否有支援,可以用下列方式:

docudment.implementation.hasFeature("Traversal")//若有支援,則為true

Treewalker介面由兩種立要物件組成,每一種物件都提供不同的過濾觀點來看物件

(1)NodeIterator物件,提供一種"平坦式"的循環觀點,來看文件中的節點,而且有過濾功能
例如,我們可以定義一個NodeIterator物件,將所有文件的內容通通過濾掉.只留下<img>,然後將這些陣列元素當成陣列傳出來,
NodeIterator物件的nextNode()和previousNOde()可以讓我們在此串列中來回移動.
注意,NodeIterator可以讓我們尋訪選定的文件部分,而無需遞迴.
我們可以在迴圈中使用NodeIterator物件,重覆呼叫nextNode(),直到我們要的節點出現為止,或直到變為null為止(表示巳達到尾端)

(2)TreeWalker物件,可以讓我們呼叫nextNode()和previousNode()來尋訪過濾後的文件,但不會將文件樹變"平坦".
TreeWalker會保留文件樹的樹結構(不過樹結構可能會在過濾時被大量修改),
我們可以用firstChild(),lastChild(),nextSibling(),previousSibling(),parentNode()等方法尋訪結結構樹.
當我們想自己尋訪過濾後的結構樹時,就可以改用TreeWalker來替代NodeIterator,不過,就無法再重覆呼叫nextNOde()來遍歷了,
或者,當我們想做比較複雜的尋訪,要自行跳過某些子系時,也可以使用TreeWalker.

Document物件定義了createNodeIterator()和createTreeWalker()來建立NodeIterator和TreeWalker物件,
想知道瀏覽器是否支援Traversal介面的方式之一是去檢測這些方法是否存在:

if(document.createNodeIterator && document.createTreeWalker){
/*可以使用Traversal API*/
}

creatNodeIterator()和createTreeWalker()的參數都是那四個,差別是它們傳回的物件型態不同,
第一個參數是尋訪要開始的節點,若我們想尋訪整個文件,應該就是Document物件,或者如果我們想尋訪文件中的子系,就其他節點.
第二個參數是一個數字,代表NodeIterator或TreeWalker應該傳回的節點型態,這個參數可以用NodeFilter物件定義的SHOW_常數的總和來求得.
第三個參數是一個選用函數,用來指定更複雜的過濾器,而不止是根據節點型弋來過濾.
第四個參數是是布林值,可以指定文件中皂個體參考節點燛在尋訪時是否展開,
當我們處理XML文件時,這個選項會用到,但若我們處理的都是HTLM文件,則可以忽略,傳false.

NodeIterator和TreeWalker最重要的特點之一,就是它們的選擇能力,它們以把不在乎的節點過濾掉.
如前所述,我們可以在createNodeIterator()和createTreeWalker()指定第二參數和第三參數(非必要)
設定我們感興趣的節點.這些參數指定兩種層的過濾,第一層次是根據節點型態來過濾.NodeFilter物件替節點型態定義了數值常數,我們可以把適當的常數加起來指定我們感興趣的節點(或使用|運算子).
例如,若我們只對Element和Text節點感興趣,可以使用下列運算式作為第二參數:
NodeFilter.SHOW_ELEMENT+NodeFilter.SHOW_TEXT

若我們只對Element節點感興趣,可以用:

NodeFiler.SHOW_ELEMENT

若我們對所有節點感興趣,不想按其型態來過濾,可以使用:

NodeFilter.SHOW_ALL

若除了註解之外都要,可以用:

~NodeFilter.SHOW_COMMENT

注意,第一層之的過濾適用個別節點,不適用它們的子節點,若第二參數是NodeFilter.SHOW_TEXT,NodeIterator或TreeWalker不會傳回Element節點給你,但也不會全部放棄,而是會尋訪到Element節點裡面,找出我們要的Text節點.

任何節點只要通第一層過濾,就可以送進第二層過濾機制,第二層過濾機制是由我們定義的函數來執行的,因此可以執行任何複雜的過濾.若我們不需要這一類的過濾機制,只要在createNodeIterator()或createTreeWalker()的第三厽數上指定null就行了,但若我們想要這一類的過濾機制,就必須傳一妴作為第三參數.

這個函數應該需要一個節點參數,而且應該評估該節點,傳回一值,來決定該節點是否要被過濾掉,有三種可能的回傳值,由三個NodeFilter常數定義,若我們的過濾器傳回NodeFilter.FILTER_ACCEPT,則NodeInterator或TreeWalker就會傳回該節點,若我們的函數傳回NodeFilter.FILTER_SKIP,節點就會被過濾掉,NodeIterator或TreeWalker不會傳回,然而,該節點的子節點仍然會被檢視,若我們用旳是TreeWalker過濾器或許會傳回NodeFilter.FILTER_REJEC,表示節點不應該傳回,其子節點也不應再檢視.
以下的例子應可以說明前面的討論(註:要看瀏覽器有無支援Traversal API,不保證一定能執行,)
例,
//定義NodeFilter函數,只接受<img>

function imgfilter(n){
if(n.tagName=='IMG') return NodeFilter.FILTER_ACCEPT;
else return NodeFilter.FILTER_SKIP;
}

//建立NodeIterator物件來尋<img>標籤

var images=document.createNodeIterator(document, //尋訪整份文件
NodeFilter.SHOW_ELEMENT,
imgfilter,
false);
//以迴圈拿出所有圖像,do some thing

var image;
while((image=images.nextNode())!=null){
image.style.visibility="hidden";//在這裡處理圖像

}


2.Range API介面

DOM Range API 只有一個Range介面,Range物件代表的是文件內容中某一連續的範圍,包含一個指定的起點和一個指定的終點.
很多應用程式在顯示文字和文時,都可以讓使用者以滑鼠拖曳來選取文年中的某一部分,像這樣來選取文件的某一部分,在觀念上來講,就相當於Range的範圍觀念
(雖然瀏覽器通常都可以讓使用者選取文件內容,目前的DOM Level 2規範沒有辦法讓使用者選取的範圍可以經由JS取得)
當文件樹中的某一節點落在一範圍內,我們通常說這個節點被選定了,即使終端使用者還沒有用Range物件做任何的選取動作,當某一範圍的起點和終點相同時,我們說這個範圍折疊起來了,就此例而言,Range物件代表的是文件中單一位置,或者是單一插入點.

Range物件提供一些方法,可以讓我們定義某一範圍的起點和終點,也可以讓我們複製或刪除範圍內的內容,也可以在範圍的起點處插入節點.Range API是選用的,
我們可以用以下的程式碼測試Range是否支援:

document.implementation.hasFeature("Range","2.0")//支援Range的話是true

(1)起點和終點

範圍的起點和終點是由兩個值指定的,第一個值是文件節點,通常是Document,Element或Text物件.第二個值是一數字,代表該節點內的某位置,當該節點是一Document或Element物件時,數字代表的就是Document或Element的子節點的位置.
例如偏移量是0,代表的就是該節點第一子節點之前的位置.偏移量1代表第一子節點後面,以及第二子節點前面的位置.當指定的點一Text節點時(或者另一個文字型態的節點,如Comment)數字代表的就是文字字元之間的位置,偏移量0指的是文字內第一字元之前的位置,而偏移量1指定的是第一字元和第二字元之間的位置,依此類推,
以這種方式來指定起點和終點,範圍就可以用來代表起點和終點之間的所有節點或字元.Range介面真正強大的地方是起點和終點不見得落在同一節點之內,因此,範圍可以橫跨好幾個Element和Text節點.

在這裡用DOM規範中使用的觀念來說明範圍代表的文件內容,文件內容以HTML的形式顯示,而範圍的內容則以粗體來表示,
例如,下列代表的範圍是從<body>節點內的位置0開始,持續到Text節點內的第8個位置,而Text節點位在<h1>節點之內:

<body><h1>Document Title</h1></body>

為了建立Range物件,可以呼叫Document物件的creatRange():

var r = document.createRange();

新建的範圍其起點和終點之值都是0,在我們用範圍做任何有的事之前,必須設定起點和終點來指定所需的文件範圍.有好幾種方式可以指定,最常用的做法是呼叫setStart()和setEnd()來指定起點和終點,參數是節點以及該節點之內的位置.

設定起點和終點比較高層次的技巧是呼叫setStartBefore(),setStartAfter(),setEndBefore(),setEndAfter(),這些方法的數是單一節點,可以將Range的起點和終點設在指定節點的前後位置.

最後,若我們想定義一範圍來代表單一Node物件,或者文件的子系,可以使用selectNode()或selectNodeContent().這兩個方法的參數都是單一節點,selectNode()會把起點和終點設在指定節點的前面,定義一圍將該節點及其子節點都包含其中.
selectNodeContent()會將範圍的起點設定指定節點的第一子節點前面,將終點設指定節點的最後節點後面.最後得到的範圍就是指定節點所有的子節點,但不包含節點自身.

(2)處理範圍
定義了範圍之後,就以做很多有趣的弗,要刪除範圍內的文件內容,只要呼叫Range物件的deleteContents()方法,當一範圍包含一部分的Text節點時,刪除的運算就有一點困難,以下列為例:

<p>this is <i>only</i>a text

呼叫delecteContents()之後,文件受影響的部分看起來會像這樣:

<p>this<i>ly</i>a test

即使<i>元素有一部分包含在Range之內,刪除之後,該元素還是殘留在文件中

若我們想從文件中把某一範圍的內容移除掉,但又想把取出來的內容留下來(可能是重新插入到別的地方),可以改用extractContents().這個方法會從文件樹中將節點移除,再插入到DocumentFragment物件內,再回傳.
當一範圍包含部分選取的節點時,該節點會殘留在文件樹中,而且其內容會照修改後的結果調整.
該節點的複本(參Node.cloneNode())會被做出來,插入到DocumentFragment之中.
若呼叫的是extractConetents()不是deleteContents(),對文件產生的效果是一樣的,但是會傳回DocumentFragment物件,內含:
is<i>on</i>

當你想在文件上做剪貼時,就可以用extractContents(),若我們想做複製運算,從文入中取出內容但不是刪除掉,可以改用cloneContents(),不用extractContents()
(要做到文書處理軟體那剪貼複製的運算要比這個複雜許多,對複雜的文件樹做簡單的範圍運算,不見得都能得到所需的剪貼效果)

除了指定要刪除或複製的文字的邊界之外,範圍的起點也可以用來指定文內的插入點.Range的insertNode()可以在範圍的起點插入指定的節點(及其子節點)到文件中.
若指定的節點巳經是文件樹的一部分,會將其從當前位罝移出,重新插入到範圍指定位置,若指定節點DocumentFragment物件,則該節點的子節點的子節點會插入進來.
Range物件另一個有用的方法是surroundContents(),這個方會把範圍的內容變成指定節點的子節點,再將該節點插入範圍在文件樹中的所圶位置,例如,我們可以傳遞新建的<i>節點給surroundContents(),就可將此範圍:

this is only a test
改成:
this is <i>only</i> a test

注意:,因為開始標籤和結標籤都必須正確排列,若範圍選取節點的某些部分,而不是Text節點時,就不能用surroundContents().
例如:前面用來說明deleteContents()的範圍就不能改用surroundContents().

Range物件還有許多其他特點,我們可以compareBoundaryPoints()來比較兩個不同範圍的邊界,以cloneRange()來複製一範圍,以toString()來取出範圍內容的純文字本(不含標籤)
範圍的起點和終點可厶用唯讀屬性startContainer,startOffset,endContainer以及endOffset取得,所有有效範圍的起點和終點在文件樹中都有共同祖先,即使是文件樹根部的Document物件,我們以用commonAncestorContainer屬找出共同的祖先.


、、、、、、、、、、、、、、、、、、、


第十一章 事件

大部分有用的JS程式都非常仰賴事件處理器,所以應該是滿重要的,不過聽說它有點複雜,因為目前存在著四類事件模型,它們來源都不一樣,而且都不相容.
1.原始事件模型,一般都視為DOM Level 0 API的一部分(就是DOM標準出來之前的),功能有限,但所有支援JS的瀏覽器都有支援.(就是將JS程式碼的字串設成某些html元素的屬性值的傳統用法)
2.標準事件模型,強而有力而且全方位的事件模型,由DOM Level 2規範定義,Netscape6和Mozilla6有支援.
3.IE事件模型,由IE4及後續版本所支援,雖然在IE5.5之前,Microsoft就有參與DOM Level 2事件模型的制作
但直到IE6,IE還是停留在自己事件模型,没有將它實作出來.
4.Netscape4事件模型,從4代直到6代都延用,不過6代以後Netscape巳支援由DOM Level 2了.

一.傳統的事件處理
一般將JS程式碼的字串設成某些html元素的屬性值的用法,都是傳統的事件模型範疇,
一般來說,事件處理器大多是被當成html標籤的一個屬性,屬性值就是我們要呼叫JS函數.
這些多都是在DOM Level 2標準出來之前就巳存在的東西,聽說來源好像也是滿雜的,不論如何,主要還是要看瀏覽器支不支援,兩大瀏覽器Netscape和IE,至少在4代之前的各版本,各自都有各自支援事件處理器,隨JS程式設計的演進,事件模型也不斷增加,新版的瀏覽器所支援的事件也多會隨之增加,最後,因為事件處器是依附在標籤裡,所以html的態度也插上一腳,HTML4規範就發布過一組支援事件處器屬性的標籤.

1.支援事件處理器的常見標籤

事件處理器引發時機備註
onabort圖像截入中斷<img>
onblur元素失去輸入焦點<button>,<input>,<label>,<select>,<textarea>,<body>
onchange在<select>元素中選取,或其它表單失去焦點,而再度得到焦點時,其值有變<input>,<select>,<textarea>
onclick滑鼠點擊,取消預設為時回傳false<a>,<area>,<input>,大多數元素
ondblclick雙點擊大多數元素
onerror載入圖像時出錯<img>
onfocus元素獲得焦點<button>,<input>,<label>,<select>,<textarea>,<body>
onkeydown按下按鍵,取消時傳回false<input>,<textarea>,<body>
onkeypress按下及放開按鍵,取消時傳回false
onkeyup放開按鍵
onmousedown按下滑鼠<a>,<area>,<img>
onmousemove滑鼠移動<a>,<area>,大多數元素
onmouseout滑鼠移開元素<a>,<area>,大多數元素
onmouseover滑鼠移過元素上方<a>,<area>,大多數元素
onmouseup滑鼠放開<a>,<area><img>,大多數元素
onset請求表單重設,傳回false會防止重設<form>
onsubmit請求表單送出,傳回false會防止送出<form>
onresize視窗尺寸有變<body>,<frameset>
onselect選取文字<input>,<textarea>
onload文件載入完畢<body>,<frameset>
onunload文件或框架(frameset)卸載<body>,<frameset>


#隨著時間的演進,去暸解在哪個瀏覽器版本支援哪個事件處理器,似乎没有義意.而且好像有很多,記記不支援的標籤可能還好一點.
聽說(聽說啦)事件大致分為兩種,一種是單純描述使用者的行為,如動動滑鼠或鍵盤的行為,除使用者的輸入行為之外没有其他額外的義意,稱作輸入事件,或低階事件.
另一種稱作語義事件,或高階事件.因為這些事件有複雜的義意,只在特定的情境下發生,如onload,表文件載入之後,onsubmit表表單被送出,這類事件通常也會伴隨輸入事件的發生.(雖然布魯克分不太清楚,有什麼差別?低階事件是很單純,不過高階好像也很單純)
就低階事件而言,通常有些標籤是顯然不太可能支援事件處理器的,比如:<br>,不就是段落嗎?段個落還要引發什麼事件???一般在<head>的標籤,有圖形外觀的標籤(如applet,字型)都不會有事件處理器.以下是一些不支援事件處器而常見的標籤
<html>,<head>,<meta>,<br>,<font>
<frame>,<frameset>,<iframe>,<style>
<applet>,<isindex>
上表第三欄的“大多數元素”指的就是上述一些常見的不支援事件處理器標籤以外的大多數標籤.
♨應該是這樣,這部分是參考JavaScript大全第四版;David Flanagan.但感覺語義不是很明,所以不是清楚

2.用法,
(1)如上述,一般來說事件處理器大多是被當成html標籤的一個屬性,屬性值就是我們要呼叫JS函數
如,< input type="button" value="按我" onclick="alter('多謝支持')">
(2)或者,也可以(用字串形式)直接指定JS程式碼,
如,< input type="button" value="按我" onclick="if(window.numclicks) numclicks++;else numclicks=1;
this value='Click #'+numclicks;">
(3)因為HTML不分大小寫,所以事件處理寫大小寫都可以,onload,onLoad,ONLOAD,都没關係.
當然,習慣上以變數的寫法如onLoad,是最一目暸然的.不過,在XML大小寫是有分的,為了跟XML相容全寫小寫如onload會比較好.此外,JS也有分大小寫(下述),總之,事件處理器習慣寫成小寫就對了.

3.新增事件處理器
除了上述,在HTML中指定JS程式程碼或JS函數之外.事件處理器也能直接設定在JS中

(1)事件處理器是JS的屬性(♨驚爆,我一直以為這種東西是函數)
咳,是這樣的,我們知道每個HTML元素在DOM的結構樹中都是一個相對應的JS物件(這没問題嘛),而每個JS物件的屬性都對應到相對HTML元素的屬性,對JS1.1和後續版本而言,同樣也適用事件處理器這種屬性.
(事件處理器是HTML元素的屬性嘛,所以也是JS物件的屬性,有道理)
此外,注意一點,JS的屬性都是小寫,所以不論HTML屬性是大寫或小寫表示,在JS中都是以小寫表示.
總之,不管是哪個環境,事件處理器就全寫小寫就對啦.

(2)要將事件處理器指定給文件的標籤,只要將我們設好的函數指定給事件處理器的屬性即可
如,以下假設的表單為例
<form name="f1">
<input name="b1" type="button" value="按我">
</form>
則,
document.f1.b1//就可以指向表單中名叫b1的按鈕(<input>標籤)
♨參考document.form,因為表單跟它的零件群都有name屬性,只接指名字就行,其他元素好像就没這麼好命了,比如連結,name這個屬性是用來拋錨的,在JS中無法像form這樣直接取得.
在最不濟的情況下,就拿殺手鐧getElementById()出來吧,id和class任何標籤應該都會有才對

document.f1.b1.onclick=function(){alert('多謝支持')}//可以在<input>中新增事件處理器

例1.
function over(){window.status="看這裡";}
function out(){window.status="";}

document.f1.b1.onmouseover=over;//把函數塞去(別打小號,這樣就變呼叫了)
document.f1.b1.onmouseout=out;
//顯示




例2
<a id="a1" href="http://beba-brook.blogspot.com/">回首頁1</a>
顯示//回首頁1

function over(){window.status="看這裡";return true;}//true一定要回傳,否則無效果
function out(){window.status="";}
document.getElementById("a1").onmouseover=over;
document.getElementById("a1").onmouseout=out;
//document.links[i].onmouseover=over;//若知道位置,不怕麻煩,就去指定位置
//document.links[i].onmouseout=out;


//跟以下在html中設事件觸發器是一樣的
<a href="http://beba-brook.blogspot.com/"
onmouseover="window.status='看這裡';return true;"
onmouseout="window.status='';">回首頁2</a>


1.老實說,對個事件處理器,一般我們所要做的事,就是把一個函數指定進去(JS的事件處理器屬性之值是函數,所以布魯克才會直覺地認為事件處理器是函數,它的結構跟方法差不多嘛,一般比喻OOP的話,會說方法就是函數,總没有人說OOP的方法,就是傳統的變數吧?)當然也不限定一定是要函數什麼的,只要是能執行的JS碼都行,不過要注意的是“把函數指定進去”就如同定義方方法一樣,是把整個函數存進去,而不是“把函數執行的結果指定進去”,所以不能帶有小括號.
2.指定status時,別的標籤回不回傳true都没關係,但超連結不行,因為它在狀態列有預設要顯示的訊息(連結的URL),所以一定要傳回true,才能將預設的顯示訊息消除,如此才有辦法,顯示我們要指定的訊息,因為訊息若不消除,它就會一直存在那裡,不設定onmouseout,將狀態列的訊息指定為空,訊息就會一直存在.若不想分辨,全部都傳回true也不會出錯,參考status

例3.
//這個函數可以作為<a>和<area>的事件處理器,確認使用者是否繼續前往,若取消就傳false放棄
function confirmLink(){
return confirm("你確定要防問:"+this.href+"?");
}
//這個函數會遍覽文件中所有的超連結,把上面的函數指定成所有超連結的事件處理器
function confirmAllLinks(){
for(var i=0;i < document.links.length;i++){
document.links[i].onclick=confirmLink;
}

}
confirmAllLinks();

1.總之呢,還是上句,對於事件處理器,們所要做的事,就是把一個函數指定進去(當然不一定非函數不可),就像方法一樣,設定事件處理器如同替為該元素(所對應的物件)定義一個新的方法,要不是一個匿名函數,直接指定進去,如上例,element.onclick=function(){alert('多謝支持')},否則就是在函數宣告出來後再指定進去,如上例,function over(){window.status="看這裡";},element.onclick=over;設定的地點,可以在JS中或在HTML中,兩者是一樣的,在JS中指定就等於在HTML中的某元素設定了事件處理的屬性,在HTML中設定事件處理器,就等於在JS中宣告了一個函數且指定在元素物件的事件處理器屬性中.
在JS中指定的另一個好處就是,我們可以隨時更改,彈性比較大,不會破壞原本HTML的版面,若寫在html中,就固定下來了
2.在JS中指定,若原先在html中有設定事件處理器,原先html中的事件處理器會被覆蓋掉


4.事件處理器的呼叫
有時,我們可能會想要在JS中設定事件處理器,但又不想破壞原本在HTML設定的事件處理器

呼叫事件處理器,直接指明是哪個事件處理器,像函數一樣呼叫就行了.
呼叫了以後,它就會執行我們為事件處理器所定下的函數
就像:document.f1.b1.onmouseover();//會去執行over()
會出現想要明確呼叫事件處理器的原因之一,是發生在“想加強”巳由HTML設定的事件處理器的時後.
若我們想要讓使用者按某個按鈕時觸發某事件,但又想保留原先在HTML設定的事件,就會需要明確地呼叫它.
如以下程式碼
function newHandler(){//要增加的新事件函數
}
var b=document.f1.b1;//取得按鈕
var oldHandler=b.onclick;//儲存舊的事件處理器
b.onclick=function(){oldHandler();newHandler();}//指定新的事件處理器,點擊之後會觸發兩個函數

5.事件處理器的回傳值
一般來說,我們都可以傳回false取消事件的發生,(♨某物件的事件處理器屬性之值是函數,函數傳回值也没什麼好奇怪的吧)
可以回傳false的事件處理器有:onsubmit,onkeydown,onkeypress,onmousedown,onmouseup,onrest.
(上表的第二欄有註明)
唯一一個不是傳回false取消事件的例外,就是在連結使用window.status,它要回傳true,才能取消預設在狀態列顯示的超連結URL.♨好像挺合理的啊,取消我們自己訂的事件要傳回false,取消系統預設的事件,不傳回true要傳回什麼?
例,
//如我們可用Form物件的onsubmit事件處理器來執行表單驗證工作,而且發現使用者有空白的欄位没有填,onsubmit就會回傳false使表單不被送出.
<form action="search.cgi"
onsubmit="if(this.slements[0].value.length==0)return false;">
< type="type">
♨可以參考看看yahoo的
function check ()
{
var thisForm = document.AccountForm;
var alertStr = check_uid(thisForm.uid.value);
alertStr += check_passwd(thisForm.pw1.value, thisForm.pw2.value);
alertStr += check_ht(thisForm.ht.value);
if( alertStr != '' ) {
alert( alertStr );
return false;
}
return true;
}
<form name=AccountForm action="preg" method=post onsubmit="return check();" align=center>


6.關鍵字this
this指的就是目前的物件.
所以...在事件處理器中,this這個關鍵字指的就是,事件處理器所屬的元素.

因為設定事件處理器如同替為該元素(所對應的物件)定義一個新的方法,所以當事件處理器被呼叫時,就會從發生該事件的元素來呼叫這個方法,所以this指的就是事件處理器所隸屬的元素.♨總之就是這樣,知道有這件就對了
假設我們有個物件o,o有個方法omethod,
比較一下這兩句:
b.onclick=o.omethod;//...(1)
b.onclick=function(){o.omethod}//...(2)

敍述(1)使得b.onclick指向o.omethod,這沒問題嘛.
但有没有作用?聽說是没有.因為當事件被觸發,JS會把它視作是b的方法,而不是o的方法,
這時this的內含的義意,指的是b而不是o.
林老師的說法是說:不要以為你有辦法騙瀏覽器去執行其它物件的處理程式,若你想這樣作就要明白地指出來,像這樣:
b.onclick=function(){o.omethod();}
♨不是很清楚,比較下例看看
例:
//延用上例的表單的例子

document.f1.b1.onclick=function(){window.alert('多謝支持')}//指定事件處理器
//document.f1.b1.onclick=window.alert('多謝支持');

7.事件處理器的範圍
待查

二.事件的DOM Level 2的標準事件模型

上述到目前為止,不管是在HTML的元素屬性或在JS相對應的物件中設事件件處理器,這種傳統的方法都是Level 0所提供的.幾乎任何瀏覽器都有提供,普及性比較高,但功能也有限,如,某個物件只能替某種事件型態註冊一種事件處理器,但DOM的事件模型就很強大了,任何元素都可以發生事件,也可以在某物件上替某種物件型態註冊任意數目的處理程式.總之就是很好很強大,但相對的,也比較複雜.

1.事件傳播(event propagation)的過程

(1).第一階段(捕捉階段)
事件會從Document物件往下傳播,經過DOM結構樹,到標的節點,
若標的(不含標的節點)上層任何一個祖先節點有設定一個捕捉事件處理器(capturing event handler),
那麼,這些處理器也會在事件傳播階段中執行.

(2).第二階段
事件傳播到標的節點本身時,設置在標的上的事件處理器就會執行(跟Level 0一樣)

(3).第三階段(bubbling phase;汽泡階段)
事件又會從標的元素經DOM結構樹往上層傳回去.
但並非所有的事件都會往上回傳,如onsubmit事件,除<form>之外,没有必要往上傳播.
一段來說,低階事件(輸入事件)會往上傳播,語義事件則不會.
如onmousedown事件,對於文件中的任何元素都可能有義意,它就會往上回傳.

2.新增事件處理器-addEventListener()方法


使用元素物件的addEventListener()為某一個元素設定事件處理器(listener;傾聽器)
addEventListener()可以讓我們把函數設定成事件處理器
(1)型態
addEventLiener("字串",函數,布林)


(2)參數
第一個參數是事件型態的名稱,
但不含名稱開頭的on.如onsubmit就是submit,onmousedown就是mousedown.

第二個參數是事件觸發時,要呼叫的處理函數(傾聽器)
當函數被呼叫時,會傳遞Event物件(唯一的參數),這個物件載有事件的資訊細節.

第三個參數是個布林值,
若是true,指定的事件處理器就會事件傳播過程的第一階段(捕捉階段)捕捉事件,
若是false,就如同一般的事件處理器,當事件直接發生在標的節點或其子孫節點時,
就會呼叫事件處理器.
例,假設巳定義了函數,validate()和handleMouseDown()
//我們可以在<form>元素定義處理submit事件的處理程式如:
document.myform.addEventListener("submit",
function(e){validate(e.target;)},
false
);

//或我們想捕捉在特定<div>元素內所有的mousedown事件,如:
var mydiv=document.getElementById("mydiv");
mydiv.addEventListener("mousedown",handleMouseDown,true);


1.因為Level 2在設定事件處理器時,是呼叫方法,而不是設定屬性,所以我們可以在某一物件上設定一個以上的事件處理器,若多次呼叫addEventListener()在同一物件上為相同的事件件型態設定一個以上的處理程式
,則當這一型態的事件在該物件被觸發時,(往上傳的或捕捉到的),所有我們設定的函數都會執行.
但我們若在某一元素上多次設定相同的處理程式,則除了第一次設定的之外,其餘的都會忽略.

2.DOM規範並没有保證某一物件的諸多處理程式的執行次序為何,所以無法認定我們設定處理程式的順序就是它們執行的順序
3.和addEventListener()相反的方法是removeEventListener(),它會把事件處理器從物件裡頭除去,這兩者都是由EventTarget介面定義的


2.this關鍵字
上巳述,在傳統的Level 0事件中當我們替一個元素設定一個函數作為事件處理器時,
該函數就會變成該元素的方法,當這個事件處理器執行時,就是視為該元素的方法來執行.
在函數中,this會指向發生該事件的元素.

對Mozilla和Netscape6而言(它們兩個在6代就支援DOM Lever2,IE到6代都没支援)
當我們以addEventListener()設定事件處理器時,this的情況和傳統情況是一樣的.
當瀏覽器呼叫該函數時,會視其為該元素的方法來呼叫.

不過,因為DOM的規範並没有這樣要求,所以不要依賴this ,別的瀏覽器不見得會出現相同的情況.
在Level 2中,我們還有currentTarget屬性可以用,它代表設定事件處理的所在物件,是Event物件的一個屬性.

3.將物件設定成事件處理器
在Java中,事件處理器是個實作EvenListener介面的物件,
要設定事件處理器,是傳遞一個物件給addEventListener().

在JS中,我們不必實作一個EvenListener物件,可以直接將函數傳給addEventListener().
若們想使用OOP的方式,可以使用類似下列函數

function registerObjectEventHandler(element,eventtype,listener,captures){
element.addEventListener(eventtype,
function(event){listener.handleEvent(event);}
captures);
}
任何函數都可以用這個函數,設定成事件處理器,只要該物件有定義一個handleEvent()方法.
handleEvent()會視為傾聽器的方法來呼叫,而this是指向傾聽器物件,不是發出該事件的元素.
這不是DOM規範的一部分,在Mozilla 0.91和Netscape6.1,可以讓事件傾聽器定義handleEvent(),
直接傳遞給addEventListener(),不需要上述的設定函數
♨林老師勒,聽的很模糊

4.事件模組

模組事件介面事件型態
HTMLeventsEventabort,blur,change,focus,load,reset,
resize,scroll,select,submit,unload
MouseEventsMouseEventclick,mousedown,mousemove,
mouseout,mouseover,mouseup
UIEventsUIEventDOMActivate,DOMFocusln,DOMFocusOut
MutationEventsMutationEventDOMAttrModified,
DOMDOMCharacterDataModified,DOMNodeInserted,
DOMNodeInsertedIntoDocument,DOMNodeRemoved,
DOMNodeRemovedFromDocument,
DOMSubtreeModified



事件型態介面是否上傳是否有預設行為支援的元素/屬性細節
abortEventYN<img>,<object>
blurEventNN<a>,<area>,<button>,
<input>,<label>,<select>,
<textarea>
changeEventYN<input>,<select>,<textarea>
clickMouseEventYYscreenX,screenY,clientX,
clientY,altkey,ctrlKey,
shiftKey,metaKey,button,
detail
errorEventYN<body>,<frameset>,
<img>,<object>
focusEventNN<a>,<area>,<button>,
<input>,<label>,<select>,
<textarea>
loadEventNN<body>,<frameset>,
<iframe>,<img>,<object>
mousedownMouseEventYYscreenX,screenY,clientX,
clientY,altkey,ctrlKey,
shiftKey,metaKey,button,
detail
mousemoveMouseEventYNscreenX,screenY,clientX,
clientY,altkey,ctrlKey,
shiftKey,metaKey
mouseoutMouseEventYYscreenX,screenY,clientX,
clientY,altkey,ctrlKey,
shiftKey,metaKey,
relatedTarget
mouseoverMouseEventYYscreenX,screenY,
clientX,clientY,altkey,ctrlKey,
shiftKey,metaKey,
relatedTarget
mouseupMouseEventYYscreenX,screenY,

clientX,clientY,altkey,ctrlKey,
shiftKey,metaKey,
button,detail
resetEventYN<form>
resizeEventYN<body>,<frameset>,
<iframe>
scrollEventYN<body>
selectEventYN<input>,<textarea>
submitEventYY<form>
unloadEventNN<body>,<frameset>
DOMActivateUIEventYYdetail
DOMAttrModifiedMutationEventYNattrName,attrChange,
prevValue,newValue,
DOMCharacterDateModifiedMutationEventYNprevValue,newValue
DOMFocusInUIEventYN
DOMFocusOutEventYN
DOMNodeInsertedMutationEventYNrelatedNode
DOMNodeInsertedIntoDocumentMutationEventNN
DOMNodeRemovedMutationEventYNrelatedNode
DOMNodeRemovedFromDocumentMutationEventNN
DOMSubtreeModifiedMutationEventYN


(a)所有介面都會實作Event介面,UIEvent和MutationEvent是Event的子介面,MouseEvent是UIEvent的子介面,所以實作UIEvent的事件物件,也會實作Event介面的所有屬性和方法,實作MouseEvent的事件物件,也會實作UIEvent和Event介面的所有屬性和方法,當事件觸發時,DOM Level 2 API會傳遞某一物件的屬性給事件處理器,提供有關該事件的詳細資訊
(b)因為DOM Level 2是模組化的,所以實作軟體可以只支援他要的那一部分,
我們可以用以下的程式程式碼來測試瀏覽器是否支援這個模組
document.implementation.hasFeature("Events","2.0")


5.混合事件
雖然DOM 規範並没有將Level 0的事件模型列入,
不過實務上支援Level 2的瀏覽器為了相容,一般都會繼續支援Level 0.也就是說,我們可以在文件中混合各種事件模型.若事件被觸發,支援Level 2的瀏覽器就是傳遞一個事件物件給事件處理器.即便處理器是以Level 0的模式設定的,它還是會這樣處理,它自行將設定成HTML屬性的事件處理器轉換成函數.而我們在JS中可以使用識別字event指向事件物件..

且Level 2有規範實作軟體,若其支援Level 0時,可以將Level 0模型設定的處理器視作用addEventListener()設定,
也就是說呢,若我們替e元素的onclick屬性設定f函數(或在HTML上設定相對應的HTML onclick屬性),就等同以下方式來設定函式
e.addEventListener("click",f,false);
(若f()被呼叫,會接收到一個事件物件作為參數.)

若將onclick屬性從f()改到g()函數, 就等同以下程式碼
e.removeEventListener("click"f,false);
e.addEventListener("click",g,false);
(理論上是這樣啦,但Level 2並没有規定,由指定onclick屬性設定的處理程器,可以經由調動removeEventListener()將它移除,( 由Level 0模式設定,用Level 2模式移除),所以這部分要看瀏覽器.)

6.合成事件.
DOM Level 2規範API可以讓我們建立和發送合成後的事件,這個API可以讓事件在程控制下產生,而非由使用者來控制,雖然這不是常用的特點,但,若我們想讓DHTML程式接受一系列事件測試,確訒認結果正確與否時,就相當有用,這個特點也可以用實作巨集式的錄放工具,自動執行某些常見的操作介面的行為.
♨講什麼啊?也不舉個例子

要產生合成事件,有三個步驟:
(a)建立事件物件
(b)設定事件物件的屬性值
(c)發送事件物件給所需的文件元素

(1) 建立事件物件
要建立事件物件,可以呼叫Document物件的createEvent(),
格式: createEvent("字串")
參數:作為參數的字串是該事件物件所屬的事件模組名稱,(注意,是“模組名稱”是“名稱”)
例,
要建立一個適用於click事件的事件物件,可以如下表示.
document.createEvent("HTMLEvents");
要建立一個適用於任何滑鼠事件的事件物件,可以如下表示.
document.createEvent("MouseEvents");
♨createEvent()的參數是事件模組的名稱,實際的事件型態名稱是傳給設定屬性值的方法,DOM規範並没有要求我們一定要用預定的名稱,我們也可以用自選的事件型態名稱來建立事件
,只要名稱開頭不是數字且不能和"DOM"(不分大小寫)一樣.
若我們以自定的事件型態名稱來設定合成事件,也必須以該事件型態名稱來設定事件處理器.


(2)設定事件物件的屬性值

建立了事件物件後,就是設定其屬性值,但...
因為事件物件的屬性值都是唯讀的,所以我們無法直接指定值給這些屬性,
不過,我們可以調用事件物件的方法來指定屬性值,不論是Event或MouseEvent,每一個事件物件都定義了一個方法,用來設定事件物件的屬性值,這個方法和事件型態有關,參數也隨之改變.但這不重要,重點是,我們只能在發送合成事件之前呼叫這種方法,當事件物件巳傳給事件處理器是,我們就無法修改事件物件的屬性了.

(3) 發送事件物件給所需的文件元素
建立了事件物件且設定了屬性以後,就可以發送出去.
我們可以傳給元素的dispatchEvent()予以發送, dispatchEvent()是由EventTarget介面定義的,所以,何任節點只要有支援addEventListener()和removeEventListener(),都可以用這個方法.

發送事件的對象元素就變成事件標的,而事件物件就會跑一遍事件傳播的階段.
在事件傳播的每一階段,我們建立的事件物件會傳給任何我們在設定事件時替此事件型態設定的處理程式,當事件傳播完成時,dispatchEvent()會傳回來,
若事件物件上有任何處理程式呼叫preventDefault(),則回傳值為false,否則為true.
♨林老師哩,你到底在講什麼?


第十二章 JS&CSS;DHTML

1.CSS(Cascading Style Sheet)

(1)CSS的目標:
將文件內容(文件結構)和文件外觀分離

(2)CSS指:階層性(Cascading)的樣式表
階層(Cascading)這個名詞說明套用到文件中指定元素的樣式規則來自不同資源階層

(3)CSS版本
CSS到目前至少有兩種版本
CSS1:定義了顏色,字體,邊界等基本樣式的屬性(1996年10月),Netscape4和IE4至少都實作了此階段的部分的CSS樣式.
CSS2:第二階段的CSS,定義了如元素絕對位置定位等更進階的屬性(1998年5月),至少第6代的瀏覽器才有支援
CSS標準第三版的研究仍在進行中,在W3C官網可以找到CSS規範和草案(http://www.w3.org/Style/CSS/)

Cascading指的是CSS的特性,而整個CSS的作用,其實就是主宰外觀(樣式嘛)
看完HTML可以知道,原本HTML是結構跟外觀通包.
有了CSS,結構跟外觀就可以分開了,
而原本HTML中屬於外觀的部分,可以交由CSS處理,
就是只用HTML的結構部分,或者也可選擇純粹結構的標籤語言XML(擴展式標籤語言)

2.DHTML
就是動態的HTML.

(1)CSS可以精準地控制文件的外觀,
不止顏色,字體,還有定位,可視性,圖層的順序等,
而我們可以用JS來控制,如切換顏色,變換字體,
還有能讓人感受深刻的如:以JS切換元素可視與否,變換元素的位置,和圖層順序等等,
所以使得網頁變得更活潑,故稱DHTML.
不過說是這樣說,DHTML終究跟真正server端的動態網頁有差距,互動能力有限
講白一點,若客戶選擇關掉JS,則設計者設計得再完美都沒用.


(2)以CSS對元素定位

屬性說明
position指定元素的定位類型,是static(靜態),或absolute(絕對),或fixed(固定),還是relative(相對)
top,left指定元素上邊緣和左邊緣的位置
bottom,right指定下邊緣和右邊緣的位置
width,height指定元素的大小
z-index指定元素相對於其他重疊元素的"堆疊順序"
display指定元素是否顯示
visiblity指定元素是否可視
clip定義元素的"裁剪區",只顯示元素在這個區域中的部分
overflow指定當元素比分配給它的空間大時應怎麼做



3.CSS2Properties介面

用JS可以改變套用到文件中各個元素的樣式屬性,DOM Level2標準定義了一個API,使得這一作用可以容易實作


因為我們以DOM API取得文件元素的參考時,我們可以取得元素by標籤名稱,也可以取得標籤byID,還能遍歷整份文件,
一但取得想套用的樣式的元素參考指標,就可以用元素的style屬性取得該元素的CSS2Properties物件,
這個物件含有與每個CSS1和CSS2樣式屬性對應的JS屬性,設定這些屬性與設定元素的style屬性相應樣式的效果一樣.
讀取這些屬性將傳回元素的style屬性所設定的CSS屬性值(若存在的話)
注意,用元素的style屬性取得的CSS2Properties物件只能指定元素的inline樣式.CSS2Proprties物件的屬性無法取得套用到元素的樣式資訊.
設定此物件的屬性後,就能定義,能有效地改寫樣式的inline樣式.

例.以下的script,它將找到文件中所有的<img>元素,並以迴圈遍歷它們,根據其大小找到作為標題廣告的<img>(或任一我們指定大小的img)
,若找到這樣的元素,就用style.visibility屬性把CSS visibility屬性設為hidden使該元素不可見(註:圖片會被隱藏,但位置會被保留)

var imgs=document.getElementsByTagName("img");//找出所有圖片
for(var i=0;i < imgs.length;i++){ //遍歷所有圖片
var img=imgs[i];
if(img.wiedh==160&&img.height==284) //若是160*284的圖片
img.style.visibility="hidden"; //隱藏
}

把這個簡單的script轉換成javascript:URL後,即將它變成書籤,存於瀏覽器中,
用書籤把廣告隱藏起來,下面是適合作書籤的script

javascript:a=document.getElementsByTagName("img");for(n=0;n < a.length;n++){
i=a[n];if(i.width==160&&i.height==284)i.style.visibility="hidden";}void 0;

書籤開頭的javascript:標示出它是一個URL,其主體是可執行的程式碼字串.
結尾處的void 0敘述將使程式碼傳回undefined,這意味著瀏覽器將繼續顯示目前的網頁(廣告的圖片除外)
若沒有void 0敘述,瀏覽器將用最後執的JS敘述傳回的值覆蓋目前的網頁.待查?

4.JS中CSS屬性的命名慣例

在CSS中許多屬性的名稱都有連字號「-」,如fon-family.但在JS中「-」符號會被解釋成「減」
所以CSS2Properties物件的屬性名稱和真正的CSS屬性名稱不同.
若CSS屬性名稱有連字號,連字號會被剔除,規則會如同變數命名規則一樣,下一個單字開頭以大寫來區隔
如:border-left-width屬性,可以透過屬性borderLeftWidth來存取.
例.
element.style.font-family="sans-serif";(錯誤)
要改成如下寫法:
element.style.fontFamily="sans-serif"

例外屬性命名規則有:float

float是JAVA及其他語言的保留字,雖然目前仍非JS的保留字,但它仍被保留以備將來使用,是ECMA擴充的保留字
解決的方法是float前冠一個css,
CSS2Properties物件中與CSS的float屬性對應的屬性是cssFloat.

5.樣式屬性的處理

(1).CSS2Properties物件的樣式屬性值都是字串(全都是字串,回傳值也是字串)

如以下的CSS碼
postition:absolute;font-family:sans-serif;background-color:#fff;

以JS要對元素e完成同樣的效果,如下

e.style.position="absolute";
e.style.fontFamily="sans-serif";
e.style.backgroundColor:"#fff";

注意到:CSS所使用的分號「;」並不是字串值的一部分

(2).所有定位的屬性值都要求要有單位(需要指明單位的CSS屬性,我們用JS表達時也要指明單位)

例,以JS將元素e的left屬性設為300像素
e.style.left="300px";
e.style.left=300; //錯誤,不是字串
e.style.left="300"//錯誤,沒有單位

e.style.left=(x0+left_margin+left_border+left_padding)+"px";//以變數表示

由於有時我們可能需將屬性設為計算後的值,也可以達成.
因為後面接著一個字串,計算後的數值資料會被自動轉換成字串(真方便,否則就是呼叫轉換函數了)
我們還可以用CSS2Properties物件取得在元素的style屬性中明確設定的CSS屬性值,叿讀取之前由JS程 式碼設定的inline樣式值
再提醒一次,重點就是:這些屬性的的回傳值是字串.
例,
var totalMarginWidth=e.style.marginLeft+e.style.marginRight;//錯誤(兩個字串相加的組合)
應改成:
var totalMarginWidth=parseInt(e.style.marginLeft)+parseInt(e.style.marginRight);
上述運算式省略兩個字串結尾傳回的單位,它假定marginLeft和marginRight屬性都用同樣的單位,若我們在nline樣式中只用像素做單位,可以用這樣的方式省略單位.

(3)複合屬性
複合屬性用加號連接即可
如margin,有margin-top,margin-right,margin-bottom,margin-left.
我們可以個別設定(可能會更容易且明暸),如:
e.style.marginTop=topMargin+"px";
e.style.marginRight=rightMargin+"px";
e.style.marginBottom=bottomMargin+"px";
e.style.marginLeft=leftMargin+"px";
或:
e.style.margin=topMargin+"px"+rightMargin+"px"+bottomMargin+"px"+leftMargin+"px";

我們也可以讀取複合屬性的值,但不值得這樣做,因為必需再解析回傳值,纣它分割出組成部分,通常很難實作,單獨查詢個別的屬性要簡單多了.

最後,再強調一次,當我們從HTMLElement的style屬性取得CSS2Properties物件時,此物件的屬性代表該元素的inline樣式特性,意即,設定這些屬性就像在元素的style屬性中設定CSS屬生一樣,它只影響一個元素,在CSS階層中比其他來源相衝突的樣式之設定優先順序更高.
這種對單一元素的精確控制正是我們用JS產生DHTML想要的效果.
但在讀取這些CSS2Properties屬性值時,只有先前用JS程式碼設定它們,或者所處理的HTML元素有設定可該屬性的inline style屬性時,其回傳值才有意義,例如,文件中的樣式將所有段落的左邊界設定為30像素,但若讀取段落元素的leftMargin屬性,除非該段落具有style屬性,覆蓋了樣式的設定,否則將得到空字串

6.編寫樣式
上述CSS2Properties介面,是用來處理CSS樣式簡單的API,因為每個HTMLElement元素都有style屬性,該屬性表示該元素的inline樣式特性.
style屬性指定指向CSS2Properties物件,它為CSS2標準定義的每個CSS樣式屬性都定義了一個JS屬性.
(也就是說上面的方法,全都是依賴style這個屬性)

以下是其他處理CSS樣式的DOM API,不過,
要注意,不保證每個API都被瀏覽器支援了(事實上許多CSS API都沒被第6代瀏覽器完整支援),
所以使用時必需測試.

(1)樣式宣告
CSSStyleDeclaration是CSS2Properties介面的父介面,因此每個文件元素的style屬性還實作CSSStyleDeclaration的屬性和方法.
因為CSSStyleDeclaration物件表示樣式屬性和其值的集合,所以可以用它作為陣列,並以樣式屬性名稱重複遍歷所有屬性.

(a)cssText,此屬性會傳回所有樣式屬性及其值的文字表示.
(b)getPropertyValue(),取得指定樣式
(c)setProperty(),設定指定樣式

它們是設定和取得某CSS2Properties物件某個樣式屬性的替代方式.
如,以下兩個敍述指的是同一件事
element.style.fontFamily="sans-serif";
element.style.setProperty("font-family","san-serif","";
)
(d)remooveProperty(),刪除指定樣式

(2)計算樣式
文件元素的style屬性只表示該元素的style屬性,不包含影響元素的其他樣式的資訊.
要確定應用到元素的完整樣式集合,需要使用Window物件的getComputeStyle()(此方法由AbstracView介面定義)
getComputeStyle()的回傳值是CSSStyleDeclaration物件,該物件描述套用到指定元素的所有樣式,我們可以假設傳回的物件亦實作了CSSProperties介面,就像其他元素的style屬性一樣
要說明元素的inline樣式和它的計算樣式之間的差別,可以考慮元素e,要判斷e是否具有inline style屬性設定的字體,可以用下列程式碼.
var inlinefont=e.style.fontFamily;
但要判斷顯示e的字集(無論inline樣式或樣式規範是否指定過它),需要用下面的程式碼
var fontfamily=window.getComputedStyle(e,null).fontFamily;
至於getComputedStyle()是由AbstractView介面定義的,下面的程式碼可以清楚地說明這一點
var fontfamily=document.defaultView.getComputedStyle(e,null).fontFamily;

getComputedStyle()傳回的樣式值是唯讀的,因為它們來自樣式階層的各個地方.這些屬性對元素樣式並沒有任何影響.此外,還應該把getComputedStyle()看作"耗時的",因為它必須遍歷整個階層,並建立一個大的CSSStyleDeclaration來表示套用到元素的吘多樣式特性

注意,除了所有HTML元素都有的style屬性外,IE5和其後的版本還定義了非標準但非常有用的currentStyle屬性,它會指向一個CSS2Properties物件,存放那個元素的計算樣式.

(3)覆蓋樣式
CSS標準規定,Web瀏覽器具有預設的樣式,該樣規定義HTML的基本顯示樣式.瀏覽器允許使用者指定使用者樣式來表示使用者的樣式首選項,覆蓋預設樣式中設定的樣式,作者樣式是由文件的作者定的樣式,即包含在文件中或文件可以連結的樣式,作者樣式將覆蓋瀏覽器的預設樣式和使用者樣式(除了!important樣式)
可以把元素的style屬性設定的inline樣式作為作者樣式的一部分.

DOM標準引入了覆蓋樣式的概念,這種樣式能覆蓋作者樣式,包括inline樣式,在覆蓋樣式中設定元素的樣式,可以在不修改文件的樣式和元素的inline樣式的情況下,改變元素的顯示樣式,可以用Document物件的getOverrideStyle()取得元素的覆蓋樣式:
var element=document.getElementById("title");
var override=document.getOverrideStyle(element,null);

該方法將傳回CSSStyleDeclaration物件(它也實作了CSS2Properties物件),可以用來改變元素的顯示樣式,注意設定覆蓋樣式和inline樣式之間的差別:
override.backgroundColor="yellow";//設定覆蓋樣式
element.style.backgroundColor="pink"//設定inline樣式

(4)建立樣式
DOMImplementation物件(用document.immplementation存取)定義了建立CSSStyleSheet物件的createCSSStyleSheet()方法,CSSStyleSheet物件定義了inserRule()方法,可以加入樣式規則到樣式.
(遺憾的是,Level 2 DOM未定義將樣式關連到文件的技術,所以目前無法使用此方法,DOM標準的將來的版本可能會修正這一點)

(5)尋訪樣式
DOM核心API可以尋訪HTML(或XML)文件,並檢測文件的每個元素,屬性和Text節點,同樣,用DOM的樣式和CSS模組,可以檢測文件中的或連結到文件的所有樣式,也可以尋訪樣式,檢測檢成樣式的規則,選擇器和樣式屬性.
(一般想建立DHTML的設計者,用前述介紹的API處理元素的inline樣式通常就足夠了.不必尋訪樣式.)

透過document.styleSheets[]陣列可以存取包含文件中或連結到文件的樣式;
如:
var ss=document.styleSheets[0];

這個陣列的元素是StyleSheet物件,表示通用的樣式,在使用CSS樣式的HTML文件中,這些物件都實作CSSStyleSheet子介面(此介面提供CSS特有的屬性和方法)
CSSStyleSheet介面還定義inserRule()和deleteRule()方法,用於加入和刪除規則
如:
var firstRule=document.styleSheet[0].cssRules[0]

CSSStyleSheet.cssRules[]陣列的元素是CSSRule物件,CSS樣式可以包含大量不同類型的規則.
除了在本章中看到的基本樣式外,還有各種"附加規則",這些規則由關鍵字@import和@page指定,在CSS參考資部分可以找到這些特殊類型的CSS規則.
CSSRule介面是通用的,可以表示任何類型的規則,它的字介面可以表示特定類型的規則,CSSRule介面的type屬性指定了特定的規則類型,CSS樣式中的大多數規則都是基本樣式規則,如:

h1{font-family:sans-serif;font-weight:bold;font-size:24pt;}

這種規則的type屬性值為CSSRule.STYLE_RULE,由額外實作CSSStyleRule介面的CSSRule物件表示.
CSSStyleRule物件定義selectorText屬性,它含有規則選擇器(在上面的規則中用字串"h1"表示)和包含規則的樣式屬性與值的style屬性(如上面規則中的font屬性)
例如:

var rule=document.styleSheets[0].cssRule[0]
var styles;
if(rule.type==CSSRule.STYLE_RULE)styles=rule.style;

CSSStyleRule.style屬性值是CSSStyleDeclaration物件,我們巳經介紹過此物件,它用來表示文件元素的inline樣式的物件是同一類型,它定義了setProperty(),removeProperty()和getPropertyValue()方法.
前面討論過,CSSStyleDeclaration物件通常都會實作CSS2Properties介面,因此它囡定義了對應於每個CSS特性的屬性

CSS2Properties物件的屬性和CSSStyleDeclaration物件getPropertyValue()會以字串形式傳回CSS樣樣式屬性的值,
這意味著在查詢特性(如font-size)的值時(或在讀取CSS2Properties物件的fontsize屬性時)得到的是數字和單位,它可能是"24pt"或"10mm"(可能不太有用).
一般來說,在取得CSS屬性的值字串值時,必須以某種方式解析它,從中擷取出想要的資料,對於clip這樣的屬性來說尤其如此,其字串語法很複雜.

作為解析字串的替代方案,CSSStyleDeclaration物件提供了另一方法,getPropertyCSSValue(),它以CSSValue物件的形式傳回CSS屬性值,而不是以字串形式傳回.
CSSValue物件的cssValueType屬性指定該物件車作的子介面,若某個屬性的值不止一個,那麼CSSValue物件有一個名為primitiveType的屬性,指定了值的類型或值的單位,有26種可能的類型,所有類型都以常表示,如:
CSSPrimitiveValue.CSS_PERCENTAGE,CSSPrimitiveValue.CSS_PX和CSSPrimitiveValue.CSS_RGBCOLOR,除了primitiveType屬性和各種常數,CSSPrimitiveValue物件還定義了各種設定和查詢物件化表的值之方法,
如:若CSSPrimiteveValue物件表示長度或百分比,那麼呼叫getFloatValue()可以取得長度,
若primitiveType屬性指出該值代表顏色,則呼叫getRGBColorValue()可以查詢顏色值.

最後,DOM CSS API還定義了一些特殊的物件型態,用來表示屬性值,RGBColor物件表示勲顏色值,
Rect物件表示矩形值(如clip屬性的值),Counter物件則代表CSS2計數器.



...