首頁 > web前端 > js教程 > 主體

JavaScript函數物件建立、參數和作用域實例詳解

伊谢尔伦
發布: 2017-07-25 11:29:03
原創
1317 人瀏覽過

函數物件

1.1 建立函數
建立JavaScript函數的一種不常用的方式(幾乎沒有人用)是透過new運算元來作用於Function“建構器」: 

var funcName = new Function( [argname1, [... argnameN,]] body );
登入後複製

參數清單中可以有任意多的參數,然後緊接著是函數體,例如: 

var add = new Function("x", "y", "return(x+y)"); 
print(add(2, 4));
登入後複製

將會列印結果:
6
但是,誰會用如此難用的方式來創建一個函數呢?如果函數體比較複雜,那拼接這個String要花費很大的力氣,所以JavaScript提供了一種語法糖,即通過字面量來創建函數:

function add(x, y){ 
return x + y; 
}
登入後複製

或: 

var add = function(x, y){ 
return x + y; 
}
登入後複製

事實上,這樣的語法糖更容易使傳統領域的程式設計師產生誤解,function關鍵字會呼叫Function來new一個對象,並將參數表和函數體準確的傳遞給Function的建構器。
通常來說,在全域作用域(作用域將在下一節詳細介紹)內聲明一個對象,只不過是對一個屬性賦值而已,比如上例中的add函數,事實上只是為全局對象添加了一個屬性,屬性名為add,而屬性的值是一個對象,即function(x, y){return x+y;},理解這一點很重要,這條語句在語法上跟: 

var str = "This is a string";
登入後複製

並無二致。都是給全域物件動態的增加一個新的屬性,如此而已。
為了說明函數跟其他的物件一樣,都是作為一個獨立的物件而存在於JavaScript的運行系統,我們不妨看這樣一個例子: 

function p(){ 
print("invoke p by ()"); 
} 
p.id = "func"; 
p.type = "function"; 
print(p); 
print(p.id+":"+p.type); 
print(p());
登入後複製

沒有錯,p雖然引用了一個匿名函數(物件),但是同時又可以擁有屬性,完全跟其他物件一樣,運行結果如下:

function (){ 
print("invoke p by ()"); 
} 
func:function 
invoke p by ()
登入後複製

1.2 函數的參數
在JavaScript中,函數的參數是比較有趣的,例如,你可以將任意多的參數傳遞給一個函數,即使這個函數宣告時並未制定形式參數,例如: 

function adPrint(str, len, option){ 
var s = str || "default"; 
var l = len || s.length; 
var o = option || "i"; 
s = s.substring(0, l); 
switch(o){ 
case "u": 
s = s.toUpperCase(); 
break; 
case "l": 
s = s.toLowerCase(); 
break; 
default: 
break; 
} 

print(s); 
} 

adPrint("Hello, world"); 
adPrint("Hello, world", 5); 
adPrint("Hello, world", 5, "l");//lower case 
adPrint("Hello, world", 5, "u");//upper case
登入後複製

函數adPrint在宣告時接受三個形式參數:要列印的字串,要列印的長度,是否轉換為大小寫的標記。但是在呼叫的時候,我們可以依序傳遞給adPrint一個參數,兩個參數,或是三個參數(甚至可以傳遞給它多於3個,沒有關係),運行結果如下: 

Hello, world 
Hello 
hello 
HELLO
登入後複製

事實上,JavaScript在處理函數的參數時,與其他編譯型的語言不一樣,解釋器傳遞給函數的是一個類似陣列的內部值,叫arguments,這個在函數物件產生的時候就被初始化了。例如我們傳遞給adPrint一個參數的情況下,其他兩個參數分別為undefined.這樣,我們可以才adPrint函數內部處理那些undefined參數,從而可以向外部公開:我們可以處理任意參數。
我們透過另一個例子來討論這個神奇的arguments:

function sum(){ 
var result = 0; 
for(var i = 0, len = arguments.length; i < len; i++){ 
var current = arguments[i]; 
if(isNaN(current)){ 
throw new Error("not a number exception"); 
}else{ 
result += current; 
} 
} 
return result; 
} 

print(sum(10, 20, 30, 40, 50)); 
print(sum(4, 8, 15, 16, 23, 42));//《迷失》上那串神奇的数字 
print(sum("new"));
登入後複製

函數sum沒有顯式的形參,而我們又可以動態的傳遞給其任意多的參數,那麼,如何在sum函數中如何引用這些參數呢?這裡就需要用到arguments這個偽數組了,運行結果如下:

150 
108 
Error: not a number exception
登入後複製

函數作用域
作用域的概念在幾乎所有的主流語言中都有體現,在JavaScript中,則有其特殊性:JavaScript中的變數作用域為函數體內有效,而無區塊作用域,我們在Java語言中,可以這樣定義for循環區塊中的下標變數:

public void method(){ 
for(int i = 0; i < obj1.length; i++){ 
//do something here; 
} 
//此时的i为未定义 
for(int i = 0; i < obj2.length; i++){ 
//do something else; 
} 
}
登入後複製

而在JavaScript中: 

function func(){ 
for(var i = 0; i < array.length; i++){ 
//do something here. 
} 
//此时i仍然有值,及I == array.length 
print(i);//i == array.length; 
}
登入後複製

JavaScript的函數是在局部作用域內運作的,在局部作用域內運行的函數體可以存取其外層的(可能是全域作用域)的變數和函數。 JavaScript的作用域為詞法作用域,所謂詞法作用域是說,其作用域為在定義時(詞法分析時)就確定下來的,而並非在執行時確定,如下例:

var str = "global"; 
function scopeTest(){ 
print(str); 
var str = "local"; 
print(str); 
} 
scopeTest();
登入後複製

運行結果是什麼?初學者很可能得出這樣的答案: 

global 
local
登入後複製

而正確的結果應該是:

undefined 
local
登入後複製

因為在函數scopeTest的定義中,預先存取了未宣告的變數str,然後才對str變數進行初始化,所以第一個print(str)會回傳undifined錯誤。那為什麼函數這個時候不去存取外部的str變數呢?這是因為,在詞法分析結束後,建構作用域鏈的時候,會將函數內定義的var變數放入該鏈,因此str在整個函數scopeTest內都是可見的(從函數體的第一行到最後一行),由於str變數本身是未定義的,程式順序執行,到第一行就會回傳未定義,第二行為str賦值,所以第三行的print(str)將返回”local”。

#

以上是JavaScript函數物件建立、參數和作用域實例詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!