spring原始碼之@Import
執行JavaScript
JavaScript通常嵌在網際網路頁中執行,再HTML頁面中嵌入執行JavaScript程式碼有兩種方式:
- 使用javascript:字首構建執行JavaScript程式碼的URL。
- 使用<script.../>元素來包含JavaScript程式碼。
對於第一種方式而言,所有可以設定URL的地方都可使用這種以javascript:作為字首的URL,當用戶觸發該URL時,javascript:之後的程式碼就會獲得執行。
如果頁面需要包含大量的JavaScript程式碼,建議將這些指令碼放在<script>標籤之間。script元素即可作為head子元素,也可作為body子元素。
<!DOCTYPE html> <html> <head> <meta name="author" content="Yeeku.H.Lee(CrazyIt.org)" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title> 直接執行的JavaScript </title> </head> <body> <a href="javascript:alert('執行JavaScript!');">執行JavaScript</a> <script type="text/javascript"> alert("直接執行的JavaScript!"); </script> </body> </html>
匯入JavaScript檔案
可以將JS指令碼單獨儲存在一個*.js檔案中再匯入即可。語法格式如下:
<script src="test.js" type="text/javascript"></script>
src:指定指令碼檔案所在的URL。
type:指定該元素內包含的指令碼語言的型別。
charset:指定外部檔案所用的字符集。
defer:指定是否延遲執行。
async:指定指令碼是否非同步執行。
使用script元素的defer推遲指令碼執行
defer屬性告訴瀏覽器要等整個頁面載入之後、解析完畢後才執行該script元素中的指令碼。
下面是初學者經常犯的一個錯誤:
<html>
<head>
<meta name="author" content="Yeeku.H.Lee(CrazyIt.org)" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title> JavaScript的執行時機 </title>
<script type="text/javascript" src="defer.js">
</script>
</head>
<body>
<div id="target"></div>
</body>
</html>
defer.js指令碼檔案程式碼如下:
var tg = document.getElementById("target");
tg.innerHTML = "瘋狂HTML 5/CSS 3/JavaScript講義";
tg.style.backgroundColor = "#aab";
上面的JS指令碼先獲取id為target的元素然後修改元素的內容和背景色。但如果使用瀏覽器瀏覽該頁面,可以看到target元素沒有改變。
因為對於HTML5以前的script元素,當瀏覽器解析到script元素時,瀏覽器會停止繼續解析、執行HTML頁面,而是根據script元素的src屬性下載對應的JS指令碼檔案,解析並執行。當瀏覽器執行JS指令碼時,瀏覽器還沒有去解析HTML後面的內容,他還不知道後面有id為target的元素,因此指令碼中的var tg = document.getElementById("target");程式碼獲取的元素不存在,所以後面的程式碼也出錯了。
解決上面的做法是:將head部分的script元素移動到body元素的最後面。此外,使用defer屬性也可:它會告訴瀏覽器必須等整個頁面載入之後、解析完畢才執行script元素中的指令碼,因此只要將script元素改為如下形式:
<script type="text/javascript" src="defer.js" defer></script>
defer屬性只能作用於外部指令碼檔案,對於script元素內嵌的指令碼不起作用。
使用script元素的async非同步執行指令碼
在傳統模式下,瀏覽器會按從上到下的方式解析HTML頁面的元素,如果頁面上出現script元素,瀏覽器會解析它,完成後再解析HTML頁面。
假設有一種極端情況,script元素匯入的指令碼檔案非常耗時,這會導致瀏覽器無法向下執行,頁面將長時間顯示一片空白。此時指定async的script元素會啟動新執行緒、非同步執行script元素匯入的指令碼檔案,瀏覽器也會繼續向下解析。
<html>
<head>
<meta name="author" content="Yeeku.H.Lee(CrazyIt.org)" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title> 非同步執行JavaScript </title>
<script type="text/javascript" src="async.js" async>
</script>
</head>
<body>
<div>瘋狂HTML 5/CSS 3/JavaScript講義</div>
</body>
</html>
async.js指令碼檔案會比較耗時,在JS迴圈完成、alert彈出之前,script元素就沒有執行完成,那麼瀏覽器就不會向下執行script後面的內容,因此頁面一片空白,但如果加了async屬性,瀏覽器就會以非同步方式執行JS檔案。
acync屬性只能作用於外部指令碼檔案。
noscript元素
noscript元素用來不支援JavaScript或禁用了JavaScript的瀏覽器顯示提示資訊。直接在該元素內放提示資訊,無需指定任何屬性。
<!DOCTYPE html>
<html>
<head>
<meta name="author" content="Yeeku.H.Lee(CrazyIt.org)" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title> noscript </title>
<script type="text/javascript" src="defer.js" defer>
</script>
</head>
<body>
<noscript>
<h1>必須支援JavaScript</h1>
<p>必須使用支援JavaScript的瀏覽器,並開啟瀏覽器的JavaScript功能</p>
</noscript>
<div id="target"></div>
</body>
</html>
資料型別和變數
定義變數的方式
- 隱式定義:直接給變數賦值。
- 顯示定義:使用var關鍵字定義變數。
隱式定義:
<script type="text/javascript">
// 隱式定義變數a
a = "Hello JavaScript";
// 使用警告框輸出a的值
alert(a);
</script>
顯式定義:
<script type="text/javascript">
//顯式宣告變數a
var a ;
//給變數a賦值,賦值後a的資料型別為布林型
a = true;
//使用警告框輸出a的值
alert(a);
</script>
型別轉換
JavaScript支援自動型別轉換:
<script type="text/javascript">
// 定義字串變數
var a = "3.145";
// 讓字串變數和數值執行算術運算
var b = a - 2;
// 讓字串變數和數值執行運算,到底是算術運算,還是字串運算呢?
var c = a + 2;
// 輸出b和c的值
alert (b + "\n" + c);
</script>
- 對於減號運算子,因為字串不支援減法運算,所以系統自動將字串轉換為數值。
- 對於加號運算,因為字串可以拼接,所以系統自動將數值轉換成字串。
- 有時候需要讓字串和數值執行加法運算,這就需要使用強制型別轉換了。
- toString():將布林值、數值等轉換成字串。
- parseInt():將字串、布林值等轉換為整數。
- parseFloat()將字串、布林值等轉換為浮點數。
如果需要讓"3.145"+2這種表示式的結果為5.145,可以使用強制轉換:
<script type="text/javascript">
// 定義值為3.145的字串變數
var a = "3.145";
// 直接相加,使用自動型別轉換。
var b = a + 2; //3.1452
// 使用強制型別轉換
var c = parseFloat(a) + 2;
alert (b + "\n" + c);
</script>
對於3.145這種可以正常轉換為數值的字串,可以成功轉換為數值,但對於包含其他字元的字串,將轉換為NaN。
當使用parseInt或parseFloat將各種型別的變數轉換為數值型別時,結果如下:
- 字串值:如果字串是一個數值字串則可以轉換為數值,否則將轉換為NaN。
- undefined、null、布林值及其他物件:一律轉換為NaN。
當使用toString將各種型別的值向字串轉換時,結果全是object。
變數作用域
在全域性範圍內(不管是否使用var)或者是不使用var定義的變數都是全域性變數;在函式內使用var定義的變數是區域性變數。
<script type="text/javascript">
// 定義全域性變數test
var test = "全域性變數";
// 定義函式myFun
function myFun()
{
// 函式內不使用var定義的age也是全域性變數
age = 20;
// 函式內使用var定義的age是區域性變數
var isMale = true;
}
myFun();
alert(test + "\n"
+ age);
alert(isMale);
</script>
test、age是全域性變數,isMale是區域性變數;在函式外使用區域性變數將會報錯。
如果全域性變數和區域性變數命名相同,則區域性變數將會覆蓋全域性變數。
<script type="text/javascript">
// 定義全域性變數test
var test = "全域性變數";
// 定義函式checkScope
function checkScope()
{
// 定義區域性變數
var test = "區域性變數";
// 輸出區域性變數
alert(test);
}
checkScope();
alert(test);
</script>
先輸出了局部變數再輸出了全域性變數,函式中的區域性變數覆蓋了全域性變數,但是在函式外使用test還是輸出全域性變數,因為區域性變數離開函式就失效了。
與Java、C等語言不同的是,JS的變數沒有塊範圍:
<script type="text/javascript">
function test(o)
{
// 定義變數i,變數i的作用範圍是整個函式
var i = 0;
if (typeof o == "object")
{
// 定義變數j,變數j的作用範圍是整個函式內,而不僅僅是在if塊內。
var j = 5;
for(var k = 0; k < 10; k++)
{
// 因為JavaScript沒有程式碼塊範圍
// 所以k的作用範圍是整個函式內,而不是迴圈體內
document.write(k);
}
}
// 即使出了迴圈體,k的值依然存在
alert(k + "\n" + j);
}
test(document);
</script>
如果使用var定義變數,那麼程式會強制定義一個新變數;
如果沒有使用var定義變數,系統將總是把該變數當成全域性變數,不管前面是否曾定義過該全域性變數。如果前面已經定義過同名的全域性變數,此時就是對已有的全域性變數賦值;如果前面沒有定義過同名的全域性變數,此時就是一個新的全域性變數。
全域性變數的作用範圍對於執行HTML事件處理一樣有效:
<html>
<head>
<meta name="author" content="Yeeku.H.Lee(CrazyIt.org)" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title> 事件處理中的區域性變數和全域性變數 </title>
<script type="text/javascript">
//定義全域性變數
var x = "全域性變數";
</script>
</head>
<body>
<!-- 在onclick事件中重新定義了x區域性變數變數 -->
<input type="button" value="區域性變數"
onclick="var x = '區域性變數'; alert('輸出x區域性變數的值:' + x);"/>
<!-- 直接輸出全域性變數x的值 -->
<input type="button" value="全域性變數 "
onclick="alert('輸出x全域性變數的值: ' + x);" />
</body>
</html>
變數提升
<script type="text/javascript">
// 定義全域性變數
var scope = "全域性變數";
function test()
{
// 變數提升,所以全域性變數被區域性變數覆蓋
// 而此時scope區域性變數尚未賦值,故此處輸出undefined
document.writeln(scope + "<br />");
// 定義scope的區域性變數,其作用範圍為整個函式內
var scope = "區域性變數";
// 再次輸出scope的值。
document.writeln(scope + "<br />");
}
test();
</script>
變數提升指的是變數宣告總是會被直譯器提升到函式體的頂部。所以上面先執行定義了局部變數。
變數提升只是提升變數宣告部分,不會提升賦值部分。
因此,上面的test函式實際上等同於如下形式:
function test()
{
var scrope;
document.writeln(scope + "<br />");
// 定義scope的區域性變數,其作用範圍為整個函式內
scope = "區域性變數";
// 再次輸出scope的值。
document.writeln(scope + "<br />");
}
所以區域性變數scope變數從函式開始時就出現了,它覆蓋了全域性變數scope,但此時還未賦值,所以輸出undefined。
JS變數提升甚至不需要定義變數的語句真正執行,只要在函式中包括了定義變數的語句,該變數就會被提升到函式頂部:
<script type="text/javascript">
var x = 100;
var y = 200;
function foo()
{
document.writeln(x + "<br>");
document.writeln(y);
if (false)
{
var x = 1;
}
return;
var y = 2;
}
// function foo()
// {
// var x, y;
// if (false)
// {
// x = 1;
// }
// return;
// y = 1;
// }
foo();
</script>
上面第10行位於條件為false的if塊內,第13行位於return之後,這兩行程式碼根本不會獲得執行的機會,但JavaScript直譯器依然會提升這兩個變數,因此foo函式等同於如下形式:
function foo()
{
var x,y;
if (false)
{
x=1;
}
return;
y=2;
}
這意味著從foo函式開始,全域性變數xy就被區域性變數xy覆蓋,在foo函式內無法訪問全域性變數xy。
let變數
使用var定義變數可能出現以下問題:
- var定義的變數沒有塊作用域。
- var定義的全域性變數會自動新增全域性window物件的屬性。
- var定義的變數會提前裝載。
let關鍵字正是為了解決上述問題出現的。
先看let定義迴圈變數:
<script type="text/javascript">
for (let i = 0; i < 10 ; i++)
{
console.log(i);
}
// 報錯:Uncaught ReferenceError: i is not defined
console.log("迴圈之外:" + i);
</script>
上面程式在for迴圈中使用let來定義迴圈計數器,這樣迴圈計數器i將只在for迴圈中有效,因此程式在迴圈體外訪問i變數時將會導致報錯。
如果將let改為var,那麼迴圈體中定義的i變數的作用域將會擴散到迴圈體外。
<script type="text/javascript">
let name = 'yeeku';
console.log(name); // 輸出yeeku
console.log(window.name); // window.name不存在
</script>
上面程式碼定義了name變數,這個變數不在任何函式內。因此它是一個全域性變數。但與使用var定義全域性變數不同的是,使用let定義的全域性變數不會變成window物件的屬性。
使用var定義的變數會提前裝載,而使用let定義的變數要等到程式流執行到定義變數的程式碼時才會裝載:
<script type="text/javascript">
var name = 'yeeku'
function func()
{
// 下面name變數不存在,因此程式導致錯誤
console.log(name);
let name = 'fkit';
console.log(name);
}
func();
</script>
上面程式先定義了一個全域性的name變數,然後函式中使用let定義了同名的name變數,此時區域性變數會覆蓋全域性變數。但由於使用let不會提前裝載,因此func函式在使用let定義區域性變數name之前訪問name變數會導致出錯。如果將let改為var,則先輸出undefined再輸出區域性變數name的值。
使用conset定義常量
使用conset定義的常量只能在定義時指定初始值且必須指定初始值。使用conset宣告常量以後不允許改變常量的值。
conset MAX_AGE = 120; //正確
MAX_AGE = 200; //語法錯誤
基本資料型別
數值型別
包括所有整型變數,也包括所有的浮點型變數。
<script type="text/javascript">
// 顯式宣告變數a , b
var a , b;
// 給a , b使用科學記數法賦值,其值應該為500
a = 5E2;
b = 1.23e-3;
// 使用警告提示框輸出變數a的值
alert(a + "\n" + b);
</script>
如果數值只有小數部分,則可以省略0:
<script type="text/javascript">
// 使用隱式變數定義全域性變數b
b = 3.12e1;
// 使用隱式變數定義全域性變數c
c = 45.0;
// 使用隱式變數定義全域性變數d
d = .34e4;
// 使用隱式變數定義全域性變數e
e = .24e-2;
// 使用警告框輸出四個全域性變數值
alert(b + '---' + c + '---' + d + '---' + e);
</script>
JS除了支援十進位制外也支援十六進位制和八進位制。十六進位制數以0X或0x開頭,9以上的數以a~f表示;八進位制數以0開頭,只能出現0到7的數值:
<script type="text/javascript">
// 顯式定義變數a
var a;
// 使用16進位制數給a賦值
a = 0x13;
// 顯式定義變數b
var b;
//使用8進位制數給b賦值
b = 014;
// 使用警告框輸出兩個變數的值
alert(a + "---" + b);
</script>
當數值變數的值超出了其表數範圍時將出現Infinity和-Infinity。
Infinity和-Infinity之間進行算術執行時結果將變成NaN。
Infinity和-Infinity可以執行比較運算,兩個Infinity總是相等的。
JS中允許除數為0,整數除0為Infinity,負數除0為-Infinity。除數和被除數都為0結果為NaN。
NaN不會與任何數值變數相等,NaN==NaN也返回false。
可以用isNaN()函式判斷某個變數是否為NaN:
<script type="text/javascript">
// 定義x的值為NaN
var x = 0 / 0;
// 判斷兩個NaN是否相等
if (x != x)
{
alert("NaN不等於NaN");
}
// 呼叫isNaN判斷變數
if (isNaN(x))
{
alert("x是一個NaN");
}
</script>
關於浮點型,注意其精度丟失的問題:
<script type="text/javascript">
// 顯式定義變數a
var a = .3333;
// 定義變數b,併為其賦值為a * 5
var b = a * 5;
// 使用對話方塊輸出b的值
alert(b);
</script>
//實際上是1.6665
字串型別
字串必須用引號,單雙都行。
JS以內建類String表示字串,有如下簡單屬性和方法:
<script type="text/javascript">
// 定義字串變數a
var a = "abc中國";
// 獲取a的長度
var b = a.length;
// 將系列的Unicode值轉換成字串
var c = String.fromCharCode(97,98,99);
// 輸出a的長度,以及字串a在索引4處的字元和
// 對應的Unicode值,以及c字串變數的值
alert(b + "---" + a.charAt(4) + "---"
+ a.charCodeAt(4) + "---" + c);
</script>
charAt():獲取字串特定索引處的字元。
charCodeAt():獲取字串中特定索引處的字元所對應的Unicode值。
length:屬性,直接返回字串長度。
toUpperCase():將字串的所有字母轉換為大寫。
toLowerCase():將字串的所有字母轉換為小寫。
fromCharCode():靜態方法,直接通過String類呼叫該方法,將一系列Unicode值轉換成字串。
indexOf():返回字串中特定字串第一次出現的位置。
lastIndexOf():返回字串中特定字串最後一次出現的位置。
substring():返回字串的某個字串。
slice():返回字串的某個子串,支援負數引數。
match():使用正則搜尋目標子字串。
search():使用正則搜尋目標子字串。
concat():用於將多個字串拼接。
split():將某個字串分割。
replace():將某個字串代替。
-
indexOf()和lastIndexOf()
<script type="text/javascript"> var a = "hellojavascript"; // 搜尋llo子串第一次出現的位置 var b = a.indexOf("llo"); // 跳過左邊3個字元,開始搜尋llo子串 var c = a.indexOf("llo" , 3); // 搜尋a子串最後一次出現的位置 var d = a.lastIndexOf("a"); alert(b + "\n" + c + "\n" + d); </script>
-
substring()和slice()
<script type="text/javascript"> var s = "abcdefg"; // 取得第1個(包括)到第5個(不包括)的子串 a = s.slice(0 , 4); // 取得第3個(包括)到第5個(不包括)的子串 b = s.slice(2 , 4); // 取得第5個(包括)到最後的子串 沒有指定end引數就一直到最後 c = s.slice(4); // 取得第4個(包括)到倒數第1個(不包括)的子串 d = s.slice(3 , -1); // 取得第4個(包括)到倒數第2個(不包括)的子串 e = s.slice(3 , -2); // 取得倒數第3個(包括)到倒數第1個(不包括)的子串 f = s.slice(-3 , -1); alert("a : " + a + "\nb : " + b + "\nc : " + c + "\nd : " + d + "\ne : " + e + "\nf : " + f ); </script>
-
match()和search()
前者返回匹配的子字串,後者返回匹配的索引值。match通過使用g標誌表示全域性匹配,返回所有匹配正則表示式的子串組成的陣列。
search()返回值為整型變數,如果搜尋到匹配子串則返回子串的索引值,否則返回-1.
<script type="text/javascript"> // 定義字串s的值 var s = "[email protected]"; // 從s中匹配正則表示式 a = s.search(/[a-z]+@d.[a-zA-Z]{2}m/); 兩個/裡面是正則表示式。a為6 // 定義字串變數str var str = "1dfd2dfs3df5"; // 查詢字串中所有單個的數值 var b = str.match(/\d/g); 增加了g選項表示全域性匹配,返回1,2,3,5 // 輸出a和b的值 alert(a + "\n" + b); </script>
布林型別
布林型別的值通常是邏輯運算的結果,或者用於標識物件的某種狀態。
例如判斷瀏覽器是否允許使用Cookie:
<script type="text/javascript">
// 如果瀏覽器支援Cookie
if (navigator.cookieEnabled)
{
alert("瀏覽器允許使用Cookie");
}
// 如果瀏覽器不支援Cookie
else
{
alert("瀏覽器禁用Cookie");
}
</script>
Undefined和null
undefined型別的值只有一個undefined,表示某個變數不存在,或者沒有為其分配值,也用於表示物件的屬性不存在。null用於表示變數的值為空。
複合型別
物件
物件是一系列命名變數、函式的集合。其中命名變數的型別既可以是基本資料型別也可以是複合型別。物件中的命名變數叫屬性,物件中的函式叫方法。
JS提供瞭如下常用內建類:
- Array:陣列類。
- Date:日期類。
- Error:錯誤類。
- Function:函式類。
- Math:數學類。
- Number:數值類。
- Object:物件類。
- String:字串類。
陣列
陣列是一系列的變數。元素型別可以不同。
<script type="text/javascript">
// 定義一個數組,定義時直接給陣列元素賦值。
var a = [3 , 5 , 23];
// 定義一個空陣列
var b = [];
// 定義一個空陣列。
var c = new Array();
// 直接為陣列元素賦值
b[0] = 'hello';
// 直接為陣列元素賦值
b[1] = 6;
// 直接為陣列元素賦值
c[5] = true;
// 直接為陣列元素賦值
c[7] = null;
// 輸出三個陣列值和陣列長度
alert(a + "\n" + b + "\n" + c
+ "\na陣列的長度:" + a.length
+ "\nb陣列的長度:" + b.length
+ "\nc陣列的長度:"+ c.length);
</script>
JS陣列作為棧使用的兩個方法:
- push(ele):元素入棧,返回入棧後陣列長度。
- pop():元素出棧,返回出棧的陣列元素。
JS陣列作為佇列使用的兩個方法:
- unshift():元素入佇列,返回長度。
- shift():元素出佇列,返回元素。
<script type="text/javascript">
// 將陣列當成棧使用
var stack = [];
// 入棧
stack.push("孫悟空");
stack.push("豬八戒");
stack.push("白骨精");
// 出棧
console.log(stack.pop());
console.log(stack.pop());
// 將陣列當成佇列使用
var queue = [];
// 入佇列
queue.unshift("瘋狂Java講義");
queue.unshift("輕量級Java EE企業應用實戰");
queue.unshift("瘋狂前端開發講義");
// 出佇列
console.log(queue.shift());
console.log(queue.shift());
</script>
Array物件還定義瞭如下方法:
- concat(value,...):為陣列新增一個或多個元素。返回追加元素後得到的陣列,但原陣列並不改變。
- join([separator]):將陣列的多個元素拼接在一起,組成字串後返回。
- reverse():反轉陣列。
- slice(start,[end]):擷取陣列在start索引和end索引之間的子陣列。省略end引數則一直到最後。返回擷取得到的子陣列,原陣列不改變。
- sort():排序。
- splice(start,deleteCount,value,...):擷取陣列從start索引、deletecount個元素,再將多個value值追加到陣列。返回陣列被擷取部分組成的新陣列。
函式
定義語法如下:
function functionName(param1,param2,...)
定義了一個簡單的函式:
<script type="text/javascript">
// 定義一個函式,定義函式時無需宣告返回值型別,也無需宣告變數型別
function judgeAge(age)
{
// 如果引數值大於60
if(age > 60)
{
alert("老人");
}
// 如果引數值大於40
else if(age > 40)
{
alert("中年人");
}
// 如果引數值大於15
else if(age > 15)
{
alert("青年人");
}
// 否則
else
{
alert("兒童");
}
}
// 呼叫函式
judgeAge(46);
</script>
要先判斷傳入的引數的資料型別,要加上if(typeof age === "number")。
運算子
賦值運算子
用=為變數指定變數值。
算術運算子
+、-、*、/、%、++、--、
++:自加。有a++、++a。
<script type="text/javascript">
var a = 5;
// 讓a先執行算術運算,然後自加
var b = a++ + 6;
alert(a + "\n" + b);
</script>
a為6,b是11。++在右邊時,程式先用a變數的值參與運算,此時a為5。
<script type="text/javascript">
var a = 5;
//讓a先執行自加,執行算術運算。
var b = ++a + 6;
alert(a + "\n" + b);
</script>
a是6,b是12。a先自加再運算。
乘方、開方等:
<script type="text/javascript">
// 定義變數a為3.2
var a = 3.2;
// 求a的5次方,並將計算結果賦為b。
var b = Math.pow(a , 5);
// 輸出b的值
alert(b);
// 求a的平方根,並將結果賦給c
var c = Math.sqrt(a);
// 輸出c的值
alert(c);
// 計算隨機數
var d = Math.random();
// 輸出隨機數d的值
alert(d);
</script>
位運算子
加強的賦值運算子
比較運算子
==:等於,變數值相同則返回true。
===:嚴格等於,比較兩個變數的值相等,資料型別也相同。
兩者的區別在於是否支援自動型別轉換。
<script type="text/javascript">
// 判斷5是否等於"5"
alert(5 == "5");
// 判斷5是否嚴格等於"5"
alert(5 === "5");
</script>
邏輯運算子
&&:與。||:或。!:非。
三目運算子
<script type="text/javascript">
// 使用三目運算子
5 > 3 ? alert("5大於3") : alert("5小3") ;
</script>
逗號運算子
將多個表示式排在一起,整個表示式返回最右邊表示式的值。
void運算子
用於強行指定表示式不會返回值。
<script type="text/javascript">
// 宣告變數a,b,c,d。
var a , b , c , d;
// 雖然最右邊的表示式為56,
// 但由於使用了void強制取消返回值,因此a的值為undefined。
a = void(b = 5, c = 7, d = 56);
// 輸出四個變數的值。
document.write('a = ' + a + ' b = '
+ b + ' c = ' + c + ' d = ' + d);
</script>
輸出:a = undefined b = 5 c = 7 d = 56
typeof和instanceof運算子
typeof用於判斷某個變數的資料型別,既可作為函式使用,比如typeof(a),也可作為一個運算子使用,比如typeof a。
instanceof:用於判斷某個變數是否為指定類的例項。
<script type="text/javascript">
// 定義一個數組
var a = [4, 5];
// 判斷a變數是否為Array的例項
alert(a instanceof Array);
// 判斷a變數是否為Object的例項
alert(a instanceof Object);
</script>
語句
語句塊
就是使用花括號包含的多個語句,語句塊是一個整體的執行流,類似於一個單獨的語句。
空語句
最簡單的就是一個;
空語句主要用於沒有迴圈體的迴圈:
<script type="text/javascript">
// 宣告一個數組
var a = [];
// 使用空語句,完成陣列的初始化
for (var i = 0 ; i < 10 ; a[i++] = i + 20);
// 遍歷陣列元素
for ( index in a)
{
document.writeln(a[index] + "<br />");
}
</script>
異常丟擲語句
語法如下:throw new Error(errorString);
<script type="text/javascript">
// 對計數器i迴圈
for (var i = 0 ; i < 10 ; i++)
{
// 在頁面輸出i
document.writeln(i + '<br />');
// 當i > 4時,丟擲使用者自定義異常
if (i > 4)
throw new Error('使用者自定義錯誤');
}
</script>
在瀏覽器的控制檯丟擲。
異常捕捉語句
使用catch捕捉異常,JavaScript程式碼執行中一旦出現異常就會跳轉到對應的catch塊。
使用try...catch...finally語法,finally可省略,有的話就會執行。
<script type="text/javascript">
try
{
for (var i = 0 ; i < 10 ; i++)
{
// 在頁面輸出i值
document.writeln(i + '<br />');
// 當i大於4時,丟擲異常
if (i > 4)
throw new Error('使用者自定義錯誤');
}
}
// 如果try塊中的程式碼出現異常,自動跳轉到catch塊執行
catch (e)
{
document.writeln('系統出現異常' + e.message + '<br/>');
}
// finally塊的程式碼總可以獲得執行的機會
finally
{
document.writeln('系統的finally塊');
}
</script>
with語句
可以避免重複書寫物件。如果with後面只有一行語句則可省略花括號。
document.writeln("A<br>");
document.writeln("B<br>");
document.writeln("C<br>");
可以使用:
with(document)
{
writeln("A<br>");
writeln("B<br>");
writeln("C<br>");
}
流程控制
分支
主要有if語句、switch語句。
通常不要省略if、else、else if 後執行塊的花括號,但如果執行塊只有一行語句時可以省略。
<script type="text/javascript">
// 定義變數a ,併為其賦值
var a = 5;
// 如果a>4,執行下面的執行體
if (a > 4)
alert('a大於4');
// 否則,執行下面的執行體
else
alert('a不大於4');
</script>
<script type="text/javascript">
// 宣告變數score,併為其賦值為C
var score = 'C';
// 執行swicth分支語句
switch (score)
{
case 'A': document.writeln("優秀.");
break;
case 'B': document.writeln("良好.");
break;
case 'C': document.writeln("中");
break;
case 'D': document.writeln("及格");
break;
case 'F': document.writeln("不及格");
break;
default: document.writeln("成績輸入錯誤");
}
</script>
while迴圈
<script type="text/javascript">
var count = 0;
// 只要count < 10,程式將一直執行迴圈體
while (count < 10)
{
document.write(count + "<br />");
count++;
}
document.write("迴圈結束!");
</script>
do while迴圈
do while 和 while的區別在於:while迴圈是先判斷迴圈條件為真再執行,do while是先執行迴圈體然後判斷迴圈條件,為真則執行下一次迴圈。
<script type="text/javascript">
// 定義變數count
var count = 0;
// 執行do while迴圈
do
{
document.write(count +"<br />");
count++;
// 當count < 10時執行下一次迴圈
}while (count < 10);
document.write("迴圈結束!");
</script>
for 迴圈
使用for 迴圈代替while迴圈
<script type="text/javascript">
for (var count = 0 ; count < 10 ; count++)
{
document.write(count + "<br />");
}
document.write("迴圈結束!");
</script>
for in 迴圈
<script type="text/javascript">
// 定義陣列
var a = ['hello' , 'javascript' , 'world'];
// 遍歷陣列的每個元素
for (str in a)
document.writeln('索引' + str + '的值是:' + a[str] + "<br />" );
</script>
break和continue
<script type="text/javascript">
// 以i為計數器迴圈
for (var i = 0 ; i < 5 ; i++)
{
// 以j為計數器迴圈
for (var j = 0 ; j < 5 ; j++)
{
document.writeln('j的值為:' + j);
// 當i >= 2時候,使用break中止迴圈。
if (i >= 2) break;
document.writeln('i值為:' + i);
document.writeln('<br />');
}
}
</script>
函式
定義函式的三種方式:
-
定義命名函式
<script type="text/javascript"> hello('yeeku'); // 定義函式hello,該函式需要一個引數 function hello(name) { alert(name + ",你好"); } </script>
-
定義匿名函式
<script type="text/javascript"> var f = function(name) { document.writeln('匿名函式<br />'); document.writeln('你好' + name); }; f('yeeku'); </script>
-
使用function類匿名函式
<script type="text/javascript"> // 定義匿名函式,並將函式賦給變數f var f = new Function('name' , "document.writeln('Function定義的函式<br />');" + "document.writeln('你好' + name);"); // 通過變數呼叫匿名函式 f('yeeku'); </script>
遞迴函式
<script type="text/javascript">
// 定義求階乘的函式
function factorial(n)
{
// 如果n的型別是數值,才執行函式
if (typeof(n) == "number" && n > 0)
{
// 當n等於1時,直接返回1
if (n == 1)
{
return 1;
}
// 當n不等於1時,通過遞迴返回值。
else
{
return n * factorial(n - 1);
}
}
// 當引數不是數值時,直接返回
else
{
alert("引數型別不對!");
}
}
// 呼叫階乘函式
alert(factorial(5));
</script>
區域性變數與區域性函式
在函式裡使用var定義的變數稱為區域性變數,在函式外定義的變數和在函式內不使用var定義的變數稱為全域性變數。區域性變數和全域性變數名稱相同,區域性會覆蓋全域性。區域性變數只能在函式內訪問。
區域性函式也在函式內定義。
<script type="text/javascript">
// 定義全域性函式
function outer()
{
// 定義第一個區域性函式
function inner1()
{
document.write("區域性函式11111<br />");
}
// 定義第二個區域性函式
function inner2()
{
document.write("區域性函式22222<br />");
}
document.write("開始測試區域性函式...<br />");
// 在函式中呼叫第一個區域性函式
inner1();
// 在函式中呼叫第二個區域性函式
inner2();
document.write("結束測試區域性函式...<br />");
}
document.write("呼叫outer之前...<br />");
// 呼叫全域性函式
outer();
document.write("呼叫outer之後...<br />");
</script>
函式、方法、物件、變數和類
函式可作為函式被呼叫,它本身也是一個物件,是Function類的例項。
<script type="text/javascript">
// 定義一個函式,並將它賦給hello變數
var hello = function(name)
{
return name + ",您好";
}
// 判斷函式是否為Function的例項、是否為Object的例項
alert("hello是否為Function物件:" + (hello instanceof Function)
+ "\nhello是否為Object物件:" + (hello instanceof Object));
alert(hello); //輸出原始碼
</script>
JavaScript的函式也是一個類,定義函式時也得到了一個與函式同名的類,該函式也是該類唯一的構造器。
因此,定義函式後有兩種方式呼叫函式:
- 直接呼叫函式:直接呼叫函式總是返回該函式體內最後一條return語句的返回值;如果該函式體內不包含return語句,則直接呼叫函式沒有任何返回值。
- 使用new關鍵字呼叫函式:通過這種方式呼叫總有一個返回值,返回值就是一個JavaScript物件。
<script type="text/javascript">
// 定義一個函式
var test = function(name)
{
return "你好," + name ;
}
// 直接呼叫函式
var rval = test('leegang');
// 將函式作為類的構造器
// 將該函式當成類使用,得到一個物件。
var obj = new test('leegang');
alert(rval + "\n" + obj);
</script>
下面定義了一個Person函式,也就是定義了一個類,該Person函式也會作為Person類唯一的構造器。定義Person函式時希望為該函式定義一個方法。
<script type="text/javascript">
// 定義了一個函式,該函式也是一個類
function Person(name , age)
{
// 將引數name的值賦給name屬性
this.name = name;
// 將引數age的值賦給age屬性
this.age = age;
// 為函式分配info方法,使用匿名函式來定義方法
this.info = function()
{
document.writeln("我的名字是:" + this.name + "<br />");
document.writeln("我的年紀是:" + this.age + "<br />");
};
}
// 建立p物件
var p = new Person('yeeku' , 29);
// 執行info方法
p.info();
</script>
被this關鍵字修飾的變數不再是區域性變數,它是該函式的例項屬性。
JavaScript的函式可以附加到某個物件上作為該物件的方法。如果沒有明確指定將函式附加到哪個物件上,該函式將附加到window物件上,作為window物件的方法。
<script type="text/javascript">
// 直接定義一個函式,並未指定該函式屬於哪個物件。
// 該物件預設屬於window物件
function hello(name)
{
document.write(name + ", 您好<br />");
}
// 以window作為呼叫者,呼叫hello函式
window.hello("孫悟空");
// 定義一個物件
var p = {
// 定義一個函式,該函式屬於p物件。
walk: function()
{
for(var i = 0 ; i < 2 ; i++)
{
document.write("慢慢地走...");
}
}
}
p.walk();
</script>
定義函式、變數時儘量不要重名,否則會出現變數值覆蓋函式的情形。
函式的例項屬性和類屬性
由於JavaScript函式不僅僅是一個函式,還是一個類,該函式還是此類唯一的構造器,只要在呼叫函式時使用new關鍵字就可以返回一個Object,這個Object不是函式的返回值,而是函式本身產生的物件。因此在JS中定義的變數不僅有區域性變數,還有例項屬性和類屬性兩種。根據函式中宣告變數的方式,函式中的變數有3種:
- 區域性變數:在函式中用var宣告的變數。
- 例項屬性:在函式中以this字首修飾的變數。
- 類屬性:在函式中以函式名字首修飾的變數。
<script type="text/javascript">
// 定義函式Person
function Person(national, age)
{
// this修飾的變數為例項屬性
this.age = age;
// Person修飾的變數為類屬性
Person.national = national;
// 以var定義的變數為區域性變數
var bb = 0;
}
// 建立Person的第一個物件p1。國籍為中國,年紀為29
var p1 = new Person('中國' , 29);
document.writeln("建立第一個Person物件<br />");
// 輸出第一個物件p1的年紀和國籍
document.writeln("p1的age屬性為" + p1.age + "<br />");
document.writeln("p1的national屬性為" + p1.national + "<br />");
document.writeln("通過Person訪問靜態national屬性為"
+ Person.national + "<br />");
// 輸出bb屬性
document.writeln("p1的bb屬性為" + p1.bb + "<br /><hr />");
// 建立Person的第二個物件p2
var p2 = new Person('美國' , 32);
document.writeln("建立兩個Person物件之後<br />");
// 再次輸出p1的年紀和國籍
document.writeln("p1的age屬性為" + p1.age + "<br />");
document.writeln("p1的national屬性為" + p1.national + "<br />");
// 輸出p2的年紀和國籍
document.writeln("p2的age屬性為" + p2.age + "<br />");
document.writeln("p2的national屬性為" + p2.national + "<br />");
// 通過類名訪問類屬性
document.writeln("通過Person訪問靜態national屬性為"
+ Person.national + "<br />");
</script>
呼叫函式的3種方式
-
直接呼叫函式
//呼叫window物件的alert方法 window.alert("測試程式碼") //呼叫p物件的walk方法 p.walk()
-
以call()方法呼叫函式
動態地呼叫函式。
例如需要定義一個形如each(array,fn)的函式,這個函式可以自動迭代處理array陣列元素,而fn函式則負責對陣列元素進行處理。此時需要在each函式中呼叫fn函式,但目前fn函式並沒確定,所以無法採用直接呼叫的方式來呼叫fn,需要用call()方法來呼叫。
語法格式:函式引用.call(呼叫者,引數1,引數2...)
<script type="text/javascript"> // 定義一個each函式 var each = function(array , fn) { for(var index in array) { // 以window為呼叫者來呼叫fn函式, // index、array[index]是傳給fn函式的引數 fn.call(null , index , array[index]); } } // 呼叫each函式,第一個引數是陣列,第二個引數是函式 each([4, 20 , 3] , function(index , ele) { document.write("第" + index + "個元素是:" + ele + "<br />"); }); </script>
-
以apply()方法呼叫函式
與call()類似,區別如下:
- 通過call呼叫函式時必須在括號中詳細列出每個引數。
- 通過apply()動態呼叫函式時,需要以陣列形式一次性傳入所有呼叫引數。
<script type="text/javascript"> // 定義一個函式 var myfun = function(a , b) { alert("a的值是:" + a + "\nb的值是:" + b); } // 以call()方法動態地呼叫函式 myfun.call(window , 12 , 23); // 以apply()方法動態地呼叫函式 myfun.apply(window , [12 , 23]); // ① var example = function(num1 , num2) { // 可以直接用arguments代表呼叫example函式時傳入的所有引數 myfun.apply(this, arguments); } example(20 , 40); // 為apply()動態呼叫傳入陣列 myfun.apply(window , [12 , 23]); </script>
函式的獨立性
<script type="text/javascript">
function Person(name)
{
this.name = name;
// 定義一個info方法
this.info = function()
{
alert("我的name是:" + this.name);
}
}
var p = new Person("yeeku");
// 呼叫p物件的info方法
p.info();
var name = "測試名稱";
// 以window物件作為呼叫者來呼叫p物件的info方法
p.info.call(window);
</script>
在Person類中定義了info()方法,但它是獨立的,程式只要通過p.info()即可引用這個函式。因此在第16行以call()呼叫,此時window物件是呼叫者,因此info()方法中的this代表的就是window物件,訪問this.name將返回測試名稱。
當使用匿名內嵌函式定義某個類的方法時,該內嵌函式也是獨立存在的,可以被分離出來使用,包括成為另一個物件的函式。
函式提升
在同一個<script.../>元素內,JS允許先呼叫函式,然後在後面在定義函式,這就是函式提升。
<script type="text/javascript">
// 呼叫add函式
console.log(add(2, 5));
// 定義add函式(會發生函式提升)
function add(a , b)
{
console.log("執行add函式");
return a + b;
}
</script>
如果使用程式先定義匿名函式,然後將匿名函式賦值給變數,依然會發生函式提升,但此時只提升被賦值的變數,函式定義本身不會被提升。
<script type="text/javascript">
// 呼叫add函式
console.log(add(2, 5));
// 定義add函式,此時只提升add變數名,函式定義不會被提升,所以會報錯。
var add = function(a , b)
{
console.log("執行add函式");
return a + b;
}
</script>
區域性函式會被提升到所在函式的頂部。同理,如果先定義匿名函式然後將匿名函式賦值給區域性變數,那麼只會提升該區域性變數的變數定義,不會提升函式定義。
如果匿名函式被賦值的變數沒有使用var宣告,那麼該變數就是全域性變數,因此該匿名函式將會變成一個全域性函式。
<script type="text/javascript">
function test(){
// 定義add函式,此時只提升add變數名,函式定義不會被提升
add = function(a , b)
{
console.log("執行add函式");
return a + b;
}
}
test();
// test()函式執行之後,該函式內定義的add變成全域性函式
console.log(add(2, 5));
</script>
如果函式名和變數名相同:
- 定義變數時只使用var定義變數,不分配初始值,此時函式優先順序更高,函式會覆蓋變數。
- 定義變數時為變數指定初始值,此時變數優先順序更高。
箭頭函式
相當於其它語言的Lambda表示式或閉包語法。
如果箭頭函式的執行體只有一條return語句,則允許省略函式執行體的花括號和return關鍵字。
如果箭頭函式的形參列表只有一個引數則允許省略形參列表的圓括號。
<script type="text/javascript">
var arr = ["yeeku", "fkit", "leegang", "crazyit"];
// 使用函式作為map()方法的引數
var newArr1 = arr.map(function(ele){
return ele.length;
});
// 使用箭頭函式作為map()方法的引數
var newArr2 = arr.map((ele) => {
return ele.length;
});
// 由於箭頭函式只有一個形參,可以省略形參列表的圓括號
// 箭頭函式執行體只有一條return語句,可以省略return關鍵字
var newArr3 = arr.map(ele => ele.length);
console.log(newArr3);
// 使用函式作為forEach()方法的引數
arr.forEach(function(ele){
console.log(ele);
});
// 使用箭頭函式作為map()方法的引數
arr.forEach((ele) => {
console.log(ele);
});
// 由於箭頭函式只有一個形參,可以省略形參列表的圓括號
// 箭頭函式執行體只有一條語句,可以省略執行體的花括號
arr.forEach(ele => console.log(ele));
</script>
與普通函式不同,箭頭函式沒有this關鍵字,對於普通函式而言,如果程式通過new呼叫函式建立物件,那麼this代表所建立的物件;如果直接呼叫普通函式,那麼該函式中的this代表全域性物件(window)。例如,下面示範了普通函式中的this關鍵字的功能:
<script type="text/javascript">
function Person() {
// Person()作為構造器使用時,this代表該構造器建立的物件
this.age = 0;
setInterval(function growUp(){
// 對於普通函式來說,直接執行該函式時,this代表全域性物件(window)
// 因此下面的this不同於Person構造器中的this
console.log(this === window);
this.age++;
}, 1000);
}
var p = new Person();
setInterval(function(){
console.log(p.age); // 此處訪問p物件的age,將總是輸出0
}, 1000);
</script>