函數
1、函數的概念
爲什麼需要函數?
那麼首先我們來看一下輸出100以內所有素數問題的解決方案
案例1:循環的嵌套
var n = Number(prompt("請輸入一個自然數:"));
var fount = false;//找到因子的標記
for(var i=2; i<=n/2; i++){
if(n%i == 0){
fount = true;
break;//找到提前結束
}
}
alert(fount?"不是素數":"是素數");
案例1的這種解決方案比較複雜,閱讀也比較困難,需要比較高超的技術才行。
案例2:應用函數
<script>
for(var n=2; n<=100; n++){
if(isPrime(n)){
document.write(n + "<br>");
}
}
function isPrime(n){
var m = Math.ceil(Math.sqrt(n));//根據相關數學定理
var found = false;//找到因子的標記
for(var i=2; i<=m; i++){
if(m%i==0){
return false;
}
}
return true;
}
</script>
案例2這種解決方案是將一個比較複雜的問題分解爲兩個較爲簡單的問題去解決,是用“量”去克服“難”和“大”的問題。
這種解決方案給我們提供了一個解決規模大、難度高的解題思路:就是將它分解爲多個規模相對較小、難度相對較低的問題去解決,如果分解後的問題還是規模大和難度高,就可以按照這個思路一直分解下去,直到分解後的問題足夠小和簡單。歸納起來就是“大事化小”。
2、定義與調用
函數的定義:function isPrime(n){
······
}
function 定義了函數的關鍵字;
isPrime 是函數的名字,和變量名一樣的命名規則和原則;
n 形式參數(形參),還有一個實際參數:函數調用:isPrime(12),這個 12 就是實際參數(實參)。
函數頭部:function這一行(是比較重要的。體現的是函數的設計)
函數體:function後面大括號裏面是代碼(體現的是函數的實現過程)
現在用案例來表示。
案例1:驗證100以內的數字都符合角谷定理
助手:
功能:判斷一個給定的數是否符合角谷定理
名稱:isJiaogu()
輸入參數:待判斷的數
輸出結果:true/false
var flag = true;
for(var n=2; n<=100; n++){
if(!isJiaogu(n)){
flag = false;
// alert("角谷定理驗證失敗!");
}
}
alert("角谷定理驗證" + (flag?"成功":"失敗"));
function isJiaogu(n){//函數的頭部
while(n != 1){
if(n%2 == 0){
n /= 2;
}else{
n = n*3+1;
}
}
return true;//函數體
}
案例2:驗證10000以內哥德巴赫猜想成立
/*
* 假設系統有一個函數能幫我們判斷大於6的偶數能否分解的素數
* 設計一下該函數
* 功能:判斷一個數能夠分解爲兩個素數之和
函數名稱:canSpilt
輸入參數:待分解的數
返回結果:true/false
* */
var flag = true;
for(var n=6; n<=10000; n+=2){
if(!canSpilt(n)){
flag = false;
}
}
alert("哥德巴赫猜想驗證" + (flag?"成功":"失敗"));
/*
* 那麼如何實現這個函數呢,好像還是不簡單,那就繼續分解
* 如果系統有一個能判斷素數的函數,那這個問題也簡單
* 設計:
* 功能:判斷一個數是否爲素數
* 名稱:isPrime()
* 輸入參數:待判斷的數
* 輸出結果:true/false
* */
function canSpilt(n){
for(var a=2; a<=n/2; a++){
if(siPrime(a) && isPrime(n-a)){
return true;
}
}
alert("哥德巴赫猜想" + (flag?"成功":"失敗"));
}
這個案例體現了“大事化小”的特性。在這個複雜的程序中,先是把一個程序分解爲兩步,然後再做,要是還是有點複雜,就再一次的分解,直到簡單可以做出來。
(自己的理解:先假設一個函數可以讓這個程序的判斷執行,然後根據這個題目的性質進行設計,然後進行判斷;實際上這個函數是不存在的,那麼我們就要用function實現這個函數)
函數的本質:(直觀理解)就是實現某個獨立功能的代碼段,或者說它就是一個數據加工的黑箱子。
3、參數傳遞
所謂參數傳遞,就是將實參的值傳遞給形參。通過調試可以確定形參在函數被調用之前是不存在的,當函數被調用的那一刻,實參被創建,並且把實參的值傳遞給形參。
參數傳遞有兩種方式:值傳遞和引用傳遞(地址傳遞)
<script>
var a = 5;
increase(a);
alert(a);
function increase(x){
x++;
}
</script>
a的值並沒有顯示預期的6,還是5。因爲形參x和實參 a是兩個不同的變量,x的變化和a沒有任何關係
②引用傳遞
var a = new Object();a.value=5;
increase(a);
alert(a.value);
function increase(x){
x.value++;
}
a.value沒有被顯示修改,但是a.value確實是加了1.因爲x就是a,或者說x是a的別名(專業一點就叫引用)。
什麼時候是引用,什麼時候值傳遞?
常規類型的參數採用的值傳遞,比如:Number,String,Boolean
對象類型採用的是引用傳遞,Object
如果希望把參數從函數中帶出來,但是函數的返回值只有一個,
4、變量的作用域
局部變量:在函數內部定義的變量,這個變量只能夠在函數的內部使用,在全局中不能夠使用。
function
localVar(){
var a=
1;
alert(a);在這裏面可以輸出1
}
localVar();
alert(a);這裏就沒有輸出
在函數中內部定義一個變量,如果沒有加上var,那麼這個變量被認作爲全局變量
function
localAllVar(){
a =
1;
}
function test(){
alert(a);
}
localAllVar();
test();
全局變量:在函數外部定義的變量,這個變量可以在全局進行使用。
var a
= 1;
function allVar(){
alert(a);
}
allVar();
衝突處理原則:就近原則。
var a
= 1;
function doubleVar(){
var a=
2;
var a=
3;
alert(a);
}
doubleVar();
當函數中定義了一個和全局變量名相同的變量,此時在函數中在定義以前使用,那麼這個變量還是函數中的變量,爲undefined,不使用全局變量。
要理解就近原則,而不是從上到下。
var a=
1;
function test(){
alert(a);
var a =2;
alert(a);
}
test();
alert(a);
在局部變量中,如果沒有聲明(var)就使用,它會默認爲是全局變量。
局部和全局同時定義了一個相同名字的變量是如何在局部裏面訪問全局變量?在局部中給變量叫上window的前綴,就可以訪問到全局的變量。
var a
= 1;
function doubleVar(){
var a=
2;
var a=
3;
// alert(a);
alert(window.a);//相當於給a加了個前綴。更容易分辨
}
doubleVar();