JavaScript也是函數式語言,它處理函數為優先對象。它是基於lambda下的理念。
理解以上概念對於學習JavaScript這門技術關系並不是很大。只是讓大家對JavaScript有個初步正確的的認識,並了解JavaScript與其它編程語言的本質區別。
文檔對象模型
文檔對象模型(Document Object Model),通常簡稱為DOM,是網站內容與JavaScript互通的接口。自JavaScript成為最常用的語言時JavaScript和DOM通常被視為獨立的實體。DOM接口用於存取、遍歷和控制HTML和XML文檔。
點擊圖片查看原始大小
下面是關於DOM的一些重要的知識:
- window對象作為全局對象,你僅需嘗試使用”window”來訪問它。Window對象下包含了你的所有要執行的JavaScript代碼。就像所有對象都包含屬性和方法。
- 屬性是存儲於對象下的變量。所有在網頁中創建的變量都會成為window對象的屬性。
- 方法是存儲在對象下的函數。在所有函數存儲在window對象下時,你可以使用’methods’引用它們。
- DOM相對於Web文檔結構創建層次結構,層次有節點組成。DOM節點有很多不同的類型,其中最重要的要數’Element’、’Text’和’Document’了.
- ‘Element’節點表示在頁面中的元素,所以如果在頁面中你有一個段落元素(’<p>’),那麼你可以通過DOM的節點來訪問它。
- ‘Text’節點表示在頁面中的所有文本(在元素中),所以如果在頁面的段落中有一些文本內容,那麼你可以通過DOM的節點來訪問它。
- ‘Document’節點表示整個文檔。(它是DOM樹的根節點)
- 另請注意,元素屬性是DOM節點本身。
- 不同的布局引擎對於DOM標准的執行是有一定的差別的。例如,使用Gecko布局引擎的FireFox浏覽器可以很好的執行(但也並不是完完全全按照W3C規范那樣),但使用Trident引擎的IE因它的很多Bug和不完全執行DOM標准而為眾人所知。這便是前端開發領域的一大痛苦之處。
下載FireBug
如果你使用Firefox浏覽器但沒有用過FireBug擴展插件,那我強烈推薦你現在就下載安裝。它是活的整個文檔結構大題圖片的非常有用的前端工具。
網頁中的JavaScript
Script元素
當你想在網站上使用JavaScript的時候,需要讓它們包含在script元素中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>JavaScript!</title>
</head>
<body>
<script type="text/javascript">
// <![CDATA[
// ]]>
</script>
</body>
</html>
正如你所見在文檔下面有script元素。其實type屬性嚴格來講應設置為”application/javascript”,但它不出所料的在IE浏覽器下無法正常工作,所以我們使用”text/javascript”或不用type屬性,如果你在意代碼W3C規范驗證的話建議你使用前者(”text/javascript”)。
記得用CDATA指定你的腳本。(點擊上圖查看大圖)
你還會注意到在script元素中我們還有一對被注釋掉的代碼行,它們告訴支持XHTML的浏覽器script元素中的內容是字符數據而不應被解釋為XHTML標記。如果你計劃在JavaScript代碼中使用’<’或’>’字符的話那它就是相當必要的。當然,如果你是用普通HTML代碼的話,那你完全可以無視它。
defer屬性
我們script元素中的JavaScript代碼會在頁面讀過程中執行,唯一的例外就是當script元素有defer屬性的時候。默認情況下,當浏覽器遇到script元素時,它會停下來並運行代碼,然後再繼續進行文檔解析。defer屬性告訴浏覽器代碼包含非變更文檔代碼而且可以稍後執行。它的唯一問題就是只在IE下可用,所以我們還是要盡量不要使用它了,了解就行:)
鏈接外部腳本
如果你想連接一個外部腳本文件,那麼你只需為你的script元素添加一個有文件地址的src屬性。把腳本文件獨立分離出來進行調用的確相對於內聯腳本來說是個好辦法,它意味著浏覽器可以緩存該文件,而且你都不用擔心那些CDATA之類的廢話。
1
<script type="text/javascript" src="my-script.js"></script>
JavaScript 要點
在我們繼續講DOM之前有必要學習一下JavaScript基礎要點,如果有些東西你理解起來有些困難,別擔心,你早晚會搞定它的。
在JavaScript種不同類型的值,它們是數值、字符串、布爾值、對象、Undefined 和 Null。
單行注釋使用兩個斜槓(//),這行內的所有內容都將被作為注釋內容理解。多行注釋使用’/*’ 和 ‘*/’完成注釋段落。
數值
在JavaScript中所有數值都被描繪成浮點值,當定義數值變量時記得不要用引號。
1
2
3
4
// 注: 要一直使用 'var' 來聲明變量:
var leftSide = 100;
var topSide = 50;
var areaOfRectangle = leftSide * topSide; // = 5000
字符串
你定義的字符串都是有字面上來看,JavaScript不會對它進行處理。一個字符串可由一連串的Unicode字符組成,並由一對雙引號或單引號包圍。
1
2
3
4
5
var firstPart = 'Hello';
var secondPart = 'World!';
var allOfIt = firstPart + ' ' + secondPart; // Hello World!
// +號進行字符串連接處理
// (它還可用於數學上的加法運算)
布爾值
布爾類型在你進行條件判斷的時候很有用,以了解是否符合指定的標准。布爾有兩個可能的值:true和false。任何使用邏輯算法的比較結果都將是布爾值。
1
2
3
4
5
6
7
5 === (3 + 2); // = true
// 你可以給變量聲明布爾值:
var veryTired = true;
// 你可以像這樣測試:
if (veryTired) {
// 你的代碼
}
上面看到的’===’是比較運算符,我們將在後面討論。
函數
函數是一個專門的對象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 使用函數操作創建一個新函數:
function myFunctionName(arg1, arg2) {
// 這裡是函數的代碼
}
// 如果你省略掉函數名,那麼你創建的是"匿名函數":
function(arg1, arg2) {
// 這裡是函數的代碼
}
// 執行函數僅需對他進行引用並使用圓括號 (附帶參數):
myFunctionName(); // 無參數
myFunctionName('foo', 'bar'); // 帶參數
// 你也可以在不聲明變量的情況下執行函數
(function(){
// 這就是所謂的自調用匿名函數
})();
數組
數組也是一個專門的對象,它可以包含任意數量的數據。要訪問數組中的數據你就必須使用數字,用以引用其在數組中的”索引”。
1
2
3
4
5
6
7
8
9
10
11
// 兩種聲名數組的不同方式,
// 字面:
var fruit = ['apple', 'lemon', 'banana'];
// 使用數組構造器:
var fruit = new Array('apple', 'lemon', 'banana');
fruit[0]; // 訪問數組中的第一個數據項 (apple)
fruit[1]; // 訪問數組中的第二個數據項 (lemon)
fruit[2]; // 訪問數組中的第三個數據項 (banana)
對象
對象是命名的的值的集合(鍵-值對),它和數組很相似,唯一的不同之處在於你可以為每個數據值指定名字。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 兩種聲明對象的不同方式,
// 字面(大括號):
var profile = {
name: 'Li',
age: 23,
job: 'Web Developer'
};
// 適用對象構造器:
var profile = new Object();
profile.name = 'Li';
profile.age = 23;
profile.job = 'Web Developer';
if/else語句
if/else語句是JavaScript中最常見的結構,它看上去就像下面這樣:
1
2
3
4
5
6
7
8
9
var legalDrinkingAge = 21;
var yourAge = 23;
if ( yourAge >= legalDrinkingAge ) {
// 我們使用'alert'來通知用戶:
alert('你可以喝水.');
} else {
alert('對不起,你不能喝水.');
}
JavaScript運算符
相比把運算符一一列舉給你我建議你看看MDC關於運算符的文檔。它會為你講解很多關於運算符的細節。我在下面的幾個例子中也為你講解了一些運算符的使用方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 加/減/乘/除
var someMaths = 2 + 3 + 4 - 10 * 100 / 2;
// 等於
if ( 2 == (5 - 3 ) { /* Do stuff */ } // == checks for eqaulity
// 不等於
if ( 2 != (5 - 3 ) { /* Do stuff */ }
// 全等運算符:
// (我建議這樣使用)
2 === 2 // Instead of 2 == 2
2 !== 3 // Instead of 2 != 3
// 賦值:
var numberOfFruit = 9;
numberOfFruit -= 2; // 等同於 "numberOfFruit = numberOfFruit - 2"
numberOfFruit += 2; // 等同於 "numberOfFruit = numberOfFruit + 2"
循環
循環在遍歷數組中的數據項或對象的所有成員時非常有用,JavaScript中最常用的循環是for和while語句。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var envatoTutSites = ['NETTUTS','PSDTUTS','AUDIOTUTS','AETUTS','VECTORTUTS'];
// WHILE循環
var counter = 0;
var lengthOfArray = envatoTutSites.length;
while (counter < lengthOfArray) {
alert(envatoTutSites[counter]);
counter++; // 等同於 counter += 1;
}
// FOR循環
// (The i stands for "iterator" - you could name it anything)
for (var i = 0, length = envatoTutSites.length; i < length; i++) {
alert(envatoTutSites[i]);
}
for循環在用於遍歷數組的時候相當受歡迎,點擊上圖查看清晰大圖
回到DOM
訪問DOM節點
假設我們有一個包含了一個段落和一個無序列表的基本XHTML文檔:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>JavaScript!</title>
</head>
<body>
<p id="intro">My first paragraph...</p>
<ul>
<li>List item 1</li>
<li>List item 1</li>
<li>List item 1</li>
<li>List item 1</li>
<li>List item 1</li>
</ul>
<script type="text/javascript">
// <![CDATA[
// ]]>
</script>
</body>
</html>
在第一個例子中我們將使用’getElementById’這個DOM方法訪問我們的段落。
(以下代碼應在script元素中)
1
2
var introParagraph = document.getElementById('intro');
// 我們現在訪問了一個DOM節點,這個DOM節點代表intro段落。
變量’introParagraph’現在指向DOM節點,我們現在可以在這個節點上做很多事情,我們可以讀取它的內容和屬性,也可以控制它的任何方面。我們可以刪除它、克隆它或將它移到DOM樹的其它位置。
我們可以使用JavaScript和DOM接口訪問現在文檔中的任何東西。所以,我們可能希望用類似的方式訪問文檔中的那個無序列表,但唯一的問題就在於它並沒有ID。你可以給它一個ID屬性並使用同樣的方法訪問它或者使用’getElementsByTagName’方法訪問它。
1
2
3
var allUnorderedLists = document.getElementsByTagName('ul');
// 'getElementsByTagName' 返回當前存在的節點集合/列表
// 它除了那一點微小的差別外其實和數組很相似。
getElementsByTagName
getElementsByTagName方法返回當前存在的節點集合/列表,它和數組的相似之處是它也有length屬性。需注意的重要一點是這些集合是’即時’的,如果你在DOM中添加了一個新元素那麼這個集合將自動自我更新。由於它和數組類似,所以我們可以使用索引來訪問其中的每個節點,從0到這個集合的總長度(減1)。
1
2
3
4
5
6
7
8
9
10
11
// 訪問單個無序列表: [0] index
var unorderedList = document.getElementsByTagName('ul')[0];
// 將UL中的列表項創建為節點列表:
var allListItems = unorderedList.getElementsByTagName('li');
// 現在我們可以使用for循環遍歷列表項:
for (var i = 0, length = allListItems.length; i < length; i++) {
// 提取其文本節點並alert它的內容:
alert( allListItems[i].firstChild.data );
}
訪問DOM中的節點和屬性,點擊上圖查看清晰大圖
遍歷DOM
術語”遍歷”就是用來描述訪問整個DOM尋找節點的行為。DOM接口為我們提供了大量的節點屬性以便我們在文檔中的所有節點自由訪問。
這些節點屬性可以方便我們訪問關聯的/挨著的節點:
- Node.childNodes:你可以使用它訪問某個元素的所有直屬子元素。它將返回一個類似數組的對象,你可以循環遍歷它。數組中的節點可以包含所有不同類型的節點,如文本節點和其它類型的元素節點。
- Node.firstChild:這個屬性等同於訪問’childNodes’數組的首項(’Element.childNodes[0]‘)。它是個捷徑。
- Node.lastChild:這個屬性等同於訪問’childNodes’數組的末項(’Element.childNodes[Element.childNodes.length-1]‘)。它也是個捷徑。
- Node.parentNode:這個屬性可以讓你訪問當前節點的父節點,僅會有唯一一個父節點,如果想訪問’祖父’級節點,可以使用’Node.parentNode.parentNode’,以此類推。
- Node.nextSibling:這個屬性可以讓你訪問DOM樹同級下的下一個節點。
- Node.previousSibling:這個屬性可以讓你訪問DOM樹同級下的上一個節點。
所以就想你看到的一樣,遍歷DOM就是如此簡單,只要你熟練運用了他的那些節點屬性。
上圖中需要注意的一點是:列表項只能在他們之間沒有空格的情況下檢索。因為在文檔中你能得到文本節點和元素節點,而’<ul>’和’<li>’之間的空格也會被當做是一個節點(文本節點)。同樣,無序列表嚴格意義上講並不是段落的下一個兄弟節點,因為在他倆之間有空格,也就是另一個節點。通常在這種情況下,你可以遍歷’childNodes’數組並測試它們的’nodeType’,'nodeType’值為1就是元素節點,2為屬性,3為文本節點。
你可以點擊這裡浏覽它的全部值列表。
就是這樣
這就是JavaScript基本運行方式,你可以使用本地DOM方法和屬性漂亮的訪問並提取文檔中的元素。現在你可以脫離那些繁瑣的框架而獨立進行基本的DOM操作了。
敬請期待下節課
好了,今天的課程先講到這裡。希望大家能在這篇’雜亂的’文章中學到些什麼。下一部分我們將專注於實例的練習,我們還可能會涉及到浏覽器事件模型。
感謝你的耐心閱讀。