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