第八章 函数
1 函数声明和函数表达式
差别一:函数声明:函数在执行代码前被创建;函数表达式是在运行阶段执行代码时创建;
差别二:函数声明创建一个与函数同名的变量,并让她指向函数;使用函数表达式,不给函数指定名称,
因此要么在代码中将函数赋给一个变量,要么以其他方式使用函数表达式;
差别三:函数声明不返回指向函数的引用;而是创建一个与函数同名的变量,并将指向函数的引用赋给它;函数表达式返回一个引用,该引用指向函数表达式创建的函数;
差别四:函数声明是完整的语句,而函数表达式是语句的一部分;
共同一:函数都可以被看做引用,函数引用是一个指向函数的值;quack函数存储在同名变量quack;fly显式存储;可以在变量中存储指向函数的引用;
共同二:可以用相同的方式处理调用他们的语句
例:
<script language="JavaScript" type="text/JavaScript"> var migrating=true; //函数表达式 var fly=function(num){ for(var i=0;i<num;i++) { console.log("Flying!"); } }; //函数声明 function quack(num){ for(var i=0;i<num;i++) { console.log("Quack!"); } } //调用 if(migrating) { var superquack=quack;//创建变量实现再引用 superquack(2); var superfly=fly; superfly(3); //quack(4); //fly(3); } </script>
2函数是一个一等值
可以将函数赋给变量;
可以将函数传递给函数;
可以从函数返回函数;
例:
<!doctype html> <html lang="en"> <head> <title>First Class</title> <meta charset="utf-8"> <style type="text/css"> </style> <script language="JavaScript" type="text/JavaScript"> //表示乘客的数据结构 var passenger=[{name:"Jane Doloop",paid:true,ticket:"coach"}, {name:"Dr.Evel",paid:true,ticket:"firstclass"}, {name:"Sue proprty",paid:false,ticket:"firstclass"}, {name:"John Funcall",paid:true,ticket:"coach"} ]; //方法一:传统分步检验函数 /* //检查是否买票 function checkPaid(passenger){ for(var i=0;i<passenger.length;i++) if(!passenger[i].paid) { console.log("The plane can't take off:"+passenger[i].name+" hasn't paid!"); return false; } return true; } //检查是否乘客在禁飞名单 function checkNoFly(passenger){ for(var i=0;i<passenger.length;i++) if(passenger[i].name=="Dr.Evel") { console.log("The plane can't take off:"+passenger[i].name+" is on the no-fly-list!"); return false; } return true; } //打印乘客姓名 function printPassenger(passenger){ for(var i=0;i<passenger.length;i++){ console.log(passenger[i].name) } } //主调函数 printPassenger(passenger); if(checkPaid(passenger)) { if(checkNoFly(passenger)) console.log("The plane could take off!"); } */ //方法二:传递函数简化代码 //迭代乘客 function processPassenger(passenger,testFunction) { for(var i=0;i<passenger.length;i++) if(testFunction(passenger[i])) return false; return true; } //打印乘客名单 function printPassenger(passenger) { var ifpaid; if(passenger.paid) ifpaid="已"; else ifpaid="未"; console.log(passenger.name+" "+ifpaid+"购票"); } //禁飞名单检测 function checkNoFlyList(passenger) { return (passenger.name==="Dr.Evel"); } //检查乘客是否已买票 function checkNotpaid(passenger) { return (!passenger.paid); } //打印乘客名单 processPassenger(passenger,printPassenger); //向函数传递函数 var allCanFly=processPassenger(passenger,checkNoFlyList); if(!allCanFly) console.log("The plane can't take off:we have a passenger on the no-fly-list!"); var allPaid=processPassenger(passenger,checkNotpaid) if(!allPaid) console.log("The plane can't take off:not everyone has paid!"); //乘客点饮料 function createDrinkOrder(passenger) { var orderFunction;//创建一个变量用于存储要返回的函数 if (passenger.ticket==="firstclass") { orderFunction=function(){ alert("Would you like a cocktail or wine?"); }; }else{ orderFunction=function(){ alert("Your choice is cola or water."); }; } return orderFunction;//返回函数 } //提供服务的函数 function serverCustomer(passenger) { var getDrinkOrderFunction=createDrinkOrder(passenger);//获取返回函数 getDrinkOrderFunction();//调用函数 //让乘客点餐 //getDrinkOrderFunction(); //播放电影 //getDrinkOrderFunction(); //清理垃圾 //getDrinkOrderFunction(); } //顾客调用服务 function serverPassenger(passenger) { for(var i=0;i<passenger.length;i++) { serverCustomer(passenger[i]); } } serverPassenger(passenger); </script> </head> <body> </body> </html>
3 数组的sort方法
<!doctype html> <html lang="en"> <head> <title>Drink PAIXU</title> <meta charset="utf-8"> <style type="text/css"> </style> <script language="JavaScript" type="text/JavaScript"> var products=[{name:"Grapefruit",calories:170,color:"red",sold:8200}, {name:"Orange",calories:160,color:"orange",sold:12101}, {name:"Cola",calories:210,color:"caramel",sold:25412}, {name:"Diet",calories:0,color:"caramel",sold:43922}, {name:"Lemon",calories:200,color:"clear",sold:14983}, {name:"Raspberry",calories:180,color:"pink",sold:9427}, {name:"Root Beer",calories:200,color:"caramel",sold:9909}, {name:"Water",calories:0,color:"clear",sold:62123}, ]; // sort and display the scores console.log("\n------- sorting by sold -------"); products.sort(compareSold); printProducts(products); console.log("\n------- sorting by name -------"); products.sort(compareName); printProducts(products); console.log("\n------- sorting by calories -------"); products.sort(compareCalories); printProducts(products); console.log("\n------- sorting by color -------"); products.sort(compareColor); printProducts(products); function compareName(colaA, colaB) { if (colaA.name > colaB.name) { return 1; } else if (colaA.name === colaB.name) { return 0; } else { return -1; } } function compareCalories(colaA, colaB) { if (colaA.calories > colaB.calories) { return 1; } else if (colaA.calories === colaB.calories) { return 0; } else { return -1; } } function compareColor(colaA, colaB) { if (colaA.color > colaB.color) { return 1; } else if (colaA.color === colaB.color) { return 0; } else { return -1; } } function compareSold(colaA, colaB) { if (colaA.sold > colaB.sold) { return 1; } else if (colaA.sold === colaB.sold) { return 0; } else { return -1; } } //打印函数 function printProducts(products) { for (var i = 0; i < products.length; i++) { console.log("Name: " + products[i].name + ", Calories: " + products[i].calories + ", Color: " + products[i].color + ", Sold: " + products[i].sold); } } </script> </head> <body> </body> </html>
3 匿名函数
是没有名称的函数表达式,使用匿名函数可以让代码更简单
如:
window.onload=function(){alert("Yeah,that page loaded!");};
setTimeout(function(){alert("Time to ttake the cookies out of the oven.");},6000);
4 嵌套函数
在其他函数中定义的函数,与局部变量一样,嵌套函数的作用域也是局部的;
词法作用域:通过阅读代码可以确定变量的作用域;
*变量:在函数体内未绑定的变量;
闭包:函数和引用环境[环境为实际环境而非环境副本];
闭包应用;避免全局变量命名冲突,使用受保护的局部变量实现计数;
<!doctype html> <html lang="en"> <head> <title>Bibao Counter</title> <meta charset="utf-8"> <style type="text/css"> </style> <script language="JavaScript" type="text/JavaScript"> //原来 var count=0; function counter(){ count=count+1; return count; } console.log(counter()); console.log(counter()); console.log(counter()); //使用闭包 function makeCounter(){ var count=0; function counter(){ count=count+1; return count; } return counter; } var doCount=makeCounter();//调用makeCounter()获得闭包(函数及其环境) console.log(doCount());//除了调用doCount没有其他办法访问count console.log(doCount()); console.log(doCount()); </script> </head> <body> </body> </html>
闭包案例2——将函数表达式用作实参创建闭包
function makeTimer(doneMessage,n){ setTimeout(function(){alert(doneMessage);},n); } makeTimer("Cookies are done!",1000);
闭包案例3——利用返回对象创建闭包
function makeCounter(){ var count=0; return {//返回对象 increment:function(){//对象方法 count++; return count; } }; } var counter=makeCounter(); console.log(counter.increment());//调用对象方法
闭包案例4——利用返回且传递实参再函数创建闭包
function multN(n){ return function multBy(m){ return n*m; }; } var multBy3=multN(3); console.log("Multiplying 2:"+multBy3(2)); console.log("Multiplying 4:"+multBy3(4));
闭包案例5——使用事件处理程序来创建闭包
<!doctype html> <html lang="en"> <head> <title>Click me!</title> <meta charset="utf-8"> <style type="text/css"> </style> <script language="JavaScript" type="text/JavaScript"> //不使用闭包 /* var count=0; window.onload=function(){ var button=document.getElementById("clickme"); button.onclick=handleClick; }; function handleClick(){ var message="You clicked me "; var div=document.getElementById("message"); count++; div.innerHTML=message+count+" times!"; } */ //使用闭包 window.onload=function(){ var count=0; var message="You clicked me "; var div=document.getElementById("message"); var button=document.getElementById("clickme"); button.onclick=function(){ count++; div.innerHTML=message+count+" times!"; }; }; </script> </head> <body> <button id="clickme">Click me!</button> <div id="message"></div> </body> </html>