第八章 函數 1 函數聲明和函數表達式 差別一:函數聲明:函數在執行代碼前被創建;函數表達式是在運行階段執行代碼時創建; 差別二:函數聲明創建一個與函數同名的變數,並讓她指向函數;使用函數表達式,不給函數指定名稱, 因此要麼在代碼中將函數賦給一個變數,要麼以其他方式使用函數表達式; 差別三:函數聲明 ...
第八章 函數
1 函數聲明和函數表達式
差別一:函數聲明:函數在執行代碼前被創建;函數表達式是在運行階段執行代碼時創建;
差別二:函數聲明創建一個與函數同名的變數,並讓她指向函數;使用函數表達式,不給函數指定名稱,
因此要麼在代碼中將函數賦給一個變數,要麼以其他方式使用函數表達式;
差別三:函數聲明不返回指向函數的引用;而是創建一個與函數同名的變數,並將指向函數的引用賦給它;函數表達式返回一個引用,該引用指向函數表達式創建的函數;
差別四:函數聲明是完整的語句,而函數表達式是語句的一部分;
共同一:函數都可以被看做引用,函數引用是一個指向函數的值;quack函數存儲在同名變數quack;fly顯式存儲;可以在變數中存儲指向函數的引用;
共同二:可以用相同的方式處理調用他們的語句
例:
1 <script language="JavaScript" type="text/JavaScript"> 2 3 var migrating=true; 4 5 6 7 //函數表達式 8 9 var fly=function(num){ 10 11 for(var i=0;i<num;i++) 12 13 { 14 15 console.log("Flying!"); 16 17 } 18 19 }; 20 21 22 23 //函數聲明 24 25 function quack(num){ 26 27 for(var i=0;i<num;i++) 28 29 { 30 31 console.log("Quack!"); 32 33 } 34 35 } 36 37 38 39 //調用 40 41 if(migrating) 42 43 { 44 45 var superquack=quack;//創建變數實現再引用 46 47 superquack(2); 48 49 var superfly=fly; 50 51 superfly(3); 52 53 //quack(4); 54 55 //fly(3); 56 57 } 58 59 </script>
2函數是一個一等值
可以將函數賦給變數;
可以將函數傳遞給函數;
可以從函數返回函數;
例:
1 <!doctype html> 2 3 <html lang="en"> 4 5 <head> 6 7 <title>First Class</title> 8 9 <meta charset="utf-8"> 10 11 <style type="text/css"> 12 13 14 15 </style> 16 17 <script language="JavaScript" type="text/JavaScript"> 18 19 //表示乘客的數據結構 20 21 var passenger=[{name:"Jane Doloop",paid:true,ticket:"coach"}, 22 23 {name:"Dr.Evel",paid:true,ticket:"firstclass"}, 24 25 {name:"Sue proprty",paid:false,ticket:"firstclass"}, 26 27 {name:"John Funcall",paid:true,ticket:"coach"} 28 29 ]; 30 31 //方法一:傳統分步檢驗函數 32 33 /* 34 35 //檢查是否買票 36 37 function checkPaid(passenger){ 38 39 for(var i=0;i<passenger.length;i++) 40 41 if(!passenger[i].paid) 42 43 { 44 45 console.log("The plane can't take off:"+passenger[i].name+" hasn't paid!"); 46 47 return false; 48 49 } 50 51 return true; 52 53 } 54 55 //檢查是否乘客在禁飛名單 56 57 function checkNoFly(passenger){ 58 59 for(var i=0;i<passenger.length;i++) 60 61 if(passenger[i].name=="Dr.Evel") 62 63 { 64 65 console.log("The plane can't take off:"+passenger[i].name+" is on the no-fly-list!"); 66 67 return false; 68 69 } 70 71 return true; 72 73 } 74 75 //列印乘客姓名 76 77 function printPassenger(passenger){ 78 79 for(var i=0;i<passenger.length;i++){ 80 81 console.log(passenger[i].name) 82 83 } 84 85 } 86 87 //主調函數 88 89 printPassenger(passenger); 90 91 if(checkPaid(passenger)) 92 93 { 94 95 if(checkNoFly(passenger)) 96 97 console.log("The plane could take off!"); 98 99 } 100 101 */ 102 103 //方法二:傳遞函數簡化代碼 104 105 //迭代乘客 106 107 function processPassenger(passenger,testFunction) 108 109 { 110 111 for(var i=0;i<passenger.length;i++) 112 113 if(testFunction(passenger[i])) 114 115 return false; 116 117 return true; 118 119 } 120 121 //列印乘客名單 122 123 function printPassenger(passenger) 124 125 { 126 127 var ifpaid; 128 129 if(passenger.paid) 130 131 ifpaid="已"; 132 133 else 134 135 ifpaid="未"; 136 137 console.log(passenger.name+" "+ifpaid+"購票"); 138 139 } 140 141 //禁飛名單檢測 142 143 function checkNoFlyList(passenger) 144 145 { 146 147 return (passenger.name==="Dr.Evel"); 148 149 } 150 151 //檢查乘客是否已買票 152 153 function checkNotpaid(passenger) 154 155 { 156 157 return (!passenger.paid); 158 159 } 160 161 //列印乘客名單 162 163 processPassenger(passenger,printPassenger); 164 165 //向函數傳遞函數 166 167 var allCanFly=processPassenger(passenger,checkNoFlyList); 168 169 if(!allCanFly) 170 171 console.log("The plane can't take off:we have a passenger on the no-fly-list!"); 172 173 var allPaid=processPassenger(passenger,checkNotpaid) 174 175 if(!allPaid) 176 177 console.log("The plane can't take off:not everyone has paid!"); 178 179 180 181 //乘客點飲料 182 183 function createDrinkOrder(passenger) 184 185 { 186 187 var orderFunction;//創建一個變數用於存儲要返回的函數 188 189 if (passenger.ticket==="firstclass") 190 191 { 192 193 orderFunction=function(){ 194 195 alert("Would you like a cocktail or wine?"); 196 197 }; 198 199 }else{ 200 201 orderFunction=function(){ 202 203 alert("Your choice is cola or water."); 204 205 }; 206 207 } 208 209 return orderFunction;//返回函數 210 211 } 212 213 //提供服務的函數 214 215 function serverCustomer(passenger) 216 217 { 218 219 var getDrinkOrderFunction=createDrinkOrder(passenger);//獲取返回函數 220 221 getDrinkOrderFunction();//調用函數 222 223 //讓乘客點餐 224 225 //getDrinkOrderFunction(); 226 227 //播放電影 228 229 //getDrinkOrderFunction(); 230 231 //清理垃圾 232 233 //getDrinkOrderFunction(); 234 235 } 236 237 //顧客調用服務 238 239 function serverPassenger(passenger) 240 241 { 242 243 for(var i=0;i<passenger.length;i++) 244 245 { 246 247 serverCustomer(passenger[i]); 248 249 } 250 251 } 252 253 254 255 serverPassenger(passenger); 256 257 </script> 258 259 </head> 260 261 <body> 262 263 264 265 </body> 266 267 </html>
3 數組的sort方法
1 <!doctype html> 2 3 <html lang="en"> 4 5 <head> 6 7 <title>Drink PAIXU</title> 8 9 <meta charset="utf-8"> 10 11 <style type="text/css"> 12 13 14 15 </style> 16 17 <script language="JavaScript" type="text/JavaScript"> 18 19 var products=[{name:"Grapefruit",calories:170,color:"red",sold:8200}, 20 21 {name:"Orange",calories:160,color:"orange",sold:12101}, 22 23 {name:"Cola",calories:210,color:"caramel",sold:25412}, 24 25 {name:"Diet",calories:0,color:"caramel",sold:43922}, 26 27 {name:"Lemon",calories:200,color:"clear",sold:14983}, 28 29 {name:"Raspberry",calories:180,color:"pink",sold:9427}, 30 31 {name:"Root Beer",calories:200,color:"caramel",sold:9909}, 32 33 {name:"Water",calories:0,color:"clear",sold:62123}, 34 35 ]; 36 37 // sort and display the scores 38 39 console.log("\n------- sorting by sold -------"); 40 41 products.sort(compareSold); 42 43 printProducts(products); 44 45 46 47 console.log("\n------- sorting by name -------"); 48 49 products.sort(compareName); 50 51 printProducts(products); 52 53 54 55 console.log("\n------- sorting by calories -------"); 56 57 products.sort(compareCalories); 58 59 printProducts(products); 60 61 62 63 console.log("\n------- sorting by color -------"); 64 65 products.sort(compareColor); 66 67 printProducts(products); 68 69 70 71 function compareName(colaA, colaB) { 72 73 if (colaA.name > colaB.name) { 74 75 return 1; 76 77 } else if (colaA.name === colaB.name) { 78 79 return 0; 80 81 } else { 82 83 return -1; 84 85 } 86 87 } 88 89 90 91 function compareCalories(colaA, colaB) { 92 93 if (colaA.calories > colaB.calories) { 94 95 return 1; 96 97 } else if (colaA.calories === colaB.calories) { 98 99 return 0; 100 101 } else { 102 103 return -1; 104 105 } 106 107 } 108 109 110 111 function compareColor(colaA, colaB) { 112 113 if (colaA.color > colaB.color) { 114 115 return 1; 116 117 } else if (colaA.color === colaB.color) { 118 119 return 0; 120 121 } else { 122 123 return -1; 124 125 } 126 127 } 128 129 130 131 function compareSold(colaA, colaB) { 132 133 if (colaA.sold > colaB.sold) { 134 135 return 1; 136 137 } else if (colaA.sold === colaB.sold) { 138 139 return 0; 140 141 } else { 142 143 return -1; 144 145 } 146 147 } 148 149 //列印函數 150 151 function printProducts(products) { 152 153 for (var i = 0; i < products.length; i++) { 154 155 console.log("Name: " + products[i].name + 156 157 ", Calories: " + products[i].calories + 158 159 ", Color: " + products[i].color + 160 161 ", Sold: " + products[i].sold); 162 163 } 164 165 } 166 167 168 169 </script> 170 171 </head> 172 173 <body> 174 175 </body> 176 177 </html>
3 匿名函數
是沒有名稱的函數表達式,使用匿名函數可以讓代碼更簡單
如:
window.onload=function(){alert("Yeah,that page loaded!");};
setTimeout(function(){alert("Time to ttake the cookies out of the oven.");},6000);
4 嵌套函數
在其他函數中定義的函數,與局部變數一樣,嵌套函數的作用域也是局部的;
詞法作用域:通過閱讀代碼可以確定變數的作用域;
自由變數:在函數體內未綁定的變數;
閉包:函數和引用環境[環境為實際環境而非環境副本];
閉包應用;避免全局變數命名衝突,使用受保護的局部變數實現計數;
1 <!doctype html> 2 3 <html lang="en"> 4 5 <head> 6 7 <title>Bibao Counter</title> 8 9 <meta charset="utf-8"> 10 11 <style type="text/css"> 12 13 14 15 </style> 16 17 <script language="JavaScript" type="text/JavaScript"> 18 19 //原來 20 21 var count=0; 22 23 function counter(){ 24 25 count=count+1; 26 27 return count; 28 29 } 30 31 32 33 console.log(counter()); 34 35 console.log(counter()); 36 37 console.log(counter()); 38 39 40 41 //使用閉包 42 43 function makeCounter(){ 44 45 var count=0; 46 47 function counter(){ 48 49 count=count+1; 50 51 return count; 52 53 } 54 55 return counter; 56 57 } 58 59 var doCount=makeCounter();//調用makeCounter()獲得閉包(函數及其環境) 60 61 console.log(doCount());//除了調用doCount沒有其他辦法訪問count 62 63 console.log(doCount()); 64 65 console.log(doCount()); 66 67 </script> 68 69 </head> 70 71 <body> 72 73 74 75 </body> 76 77 </html>
閉包案例2——將函數表達式用作實參創建閉包
1 function makeTimer(doneMessage,n){ 2 3 setTimeout(function(){alert(doneMessage);},n); 4 5 } 6 7 makeTimer("Cookies are done!",1000);
閉包案例3——利用返回對象創建閉包
1 function makeCounter(){ 2 3 var count=0; 4 5 return {//返回對象 6 7 increment:function(){//對象方法 8 9 count++; 10 11 return count; 12 13 } 14 15 }; 16 17 } 18 19 var counter=makeCounter(); 20 21 console.log(counter.increment());//調用對象方法
閉包案例4——利用返回且傳遞實參再函數創建閉包
1 function multN(n){ 2 3 return function multBy(m){ 4 5 return n*m; 6 7 }; 8 9 } 10 11 12 13 var multBy3=multN(3); 14 15 console.log("Multiplying 2:"+multBy3(2)); 16 17 console.log("Multiplying 4:"+multBy3(4));
閉包案例5——使用事件處理程式來創建閉包
1 <!doctype html> 2 3 <html lang="en"> 4 5 <head> 6 7 <title>Click me!</title> 8 9 <meta charset="utf-8"> 10 11 <style type="text/css"> 12 13 14 15 </style> 16 17 <script language="JavaScript" type="text/JavaScript"> 18 19 //不使用閉包 20 21 /* 22 23 var count=0; 24 25 window.onload=function(){ 26 27 var button=document.getElementById("clickme"); 28 29 button.onclick=handleClick; 30 31 }; 32 33 function handleClick(){ 34 35 var message="You clicked me "; 36 37 var div=document.getElementById("message"); 38 39 count++; 40 41 div.innerHTML=message+count+" times!"; 42 43 } 44 45 */ 46 47 //使用閉包 48 49 window.onload=function(){ 50 51 var count=0; 52 53 var message="You clicked me "; 54 55 var div=document.getElementById("message"); 56 57 58 59 var button=document.getElementById("clickme"); 60 61 button.onclick=function(){ 62 63 count++; 64 65 div.innerHTML=message+count+" times!"; 66 67 }; 68 69 }; 70 71 </script> 72 73 </head> 74 75 <body> 76 77 <button id="clickme">Click me!</button> 78 79 <div id="message"></div> 80 81 </body> 82 83 </html>