1.函數
注意:定義函數時可以使用個數可變的參數,而且函數既可以有return語句,也可以沒有return語句;如果函數不包含return語句,它就只執行函數體中的每條語句,然后返回給調用者undefined。
使用運算符typeof來檢測參數的數據類型,使用if(!param)return;來判斷是否存在該參數,因為js是一種無類型語言,所以你不能給函數的參數制定一個數據類型,而且js也不會檢測傳遞的數據是不是那個函數所需要的類型,如果參數很重要時,就使用前面介紹的運算符進行檢測。
不可變參數js的處理:如果傳遞的參數比函數需要的個數多,那么多余的幾個參數被忽略掉,如果傳遞的參數比函數需要的個數少,那么多余的幾個參數就會被賦予undefined,在大多數情況下,這回使得函數產生錯誤。
2.嵌套函數
a,函數定義中可以嵌套其他函數的定義,但是只能在在頂層全局代碼和頂層函數代碼中,不能出現在循環或條件語句中,并且這些限制只應用于由function語句聲明的函數,函數直接量可以出現在任何js表達式中。
3.Function()構造函數
可以使用Function()構造函數和new運算符動態地定義函數, var f = new Function("x","y","return x*y;");它等價于:function f(x,y){return x*y;}
Function構造函數可以接受任意多個字符串參數,它的最后一個參數是函數的主體,其中可以包含任何js語句,語句之間用分號分隔。由于傳遞給構造函數Function()的參數中沒有一個用于說明它要創建的函數名,用Function()構造函數創建的未命名函數有時被稱作為“匿名函數”。
Function()函數存在的意義:因為Function()構造函數允許我們動態地建立和編譯一個函數,它不會將我們限制在function語句預編譯的函數體中;另一個原因是它能將函數定義為js表達式的一部分,而不是將其定義為一個語句;缺點是:這樣做每次調用一個函數時,Function()構造函數都要對它進行編譯,
4.函數直接量
函數直接量是一個表達式,它可以定義匿名函數。
function f(x){return x*x;} //function語句
var f = new Function("x","return x*x;"); //Function()構造函數
var f = function(X){return x*x;}; //函數直接量
雖然函數直接量創建的是未命名函數,但是它的語法也規定它可以指定函數名,這在編寫調用自身的遞歸函數時特別的有用,e.g
var f= function fact(x){if(x<=1)return 1; else return x*fact(x-1);}
總結:function()函數可以任意的使用,具有通用性,Function()函數和函數直接量具有很多的相似性,他們都是未命名函數(函數直接量可以有函數名,尤其是在子調用函數中),函數直接量有個重要的有點,函數直接量只被解析和編譯一次,而作為字符串傳遞給Function()構造函數的js代碼則在每次調用構造函數時只需要被解析和編譯一次。
函數最重要的特性就是他們能夠被定義和調用,但是在js中函數并不只是一種語法,還可以是數據,可以把函數賦給變量、存儲在對象的屬性中或存儲在數組的元素中,傳遞給函數。其實函數名并沒有什么實際意義,它只是保存函數的變量的名字,可以將這個函數賦給其他的變量,它仍然以相同的方式起作用,
e.g function square(x){x*x;}
var a = square(4);
var b = square;//這種情況下b引用的函數和square的作用相同
var c = b(5);
除了賦給全局變量之外,還可以將函數賦給對象的屬性,這是稱函數為方法;也可以賦給數組元素。
e.g
var a = new Object; var a = new Object();
a.square = new Function("x","return x*x";);
y = o.square(16);
e.g
var a = new Array(3);
a[0] = function(x){return x*x;};
a[1] = 20;
a[2] = a[0](a[1]);
除這些之外,如何將函數作為參數傳遞給其他函數,
e.g
function add(x,y){return x+y;}
function subtract(x,y){return x-y;}
function multiply(x,y){return x*y;}
function dibide(x,y){return x/y;}
function operate(operator,operand1,operand2){
return operator(operand1,operand2);
}
var i = operate(add,operate(add,2,3),operate(multiply,4,5));
var operators = new Object();
operators["add"] = function(x,y){return x+y;}
operators["multiply"] = function(x,y){return x*y;}
operators["divide"] = function(x,y){return x/y;}
operators["pow"] = Math.pow;
function operate2(op_name,operand1,operand2){
if(operators[op_name] == null)return "unknow operator";
else return operators[op_name](operand1,operand2);
}
var j = operate2('add',"hello",operate2("add","","world"));
var k = operate2('pow',10,2);
5.函數的作用域,調用對象
函數的作用域中除了全局變量、函數內部的局部變量和形式參數外,函數還定義了一個特殊屬性,
arguments,這個屬性應用了另外一個特殊的對象-----Arguments對象,因為arguments屬性是調用對象的一個屬性,所以它的狀態和局部變量以及函數的形式參數是相同的。
所以arguments標識符被看做是保留字,不能將它作為變量名或形式參數名。
6.Arguments對象
arguments它具有特殊的意義,是調用對象的一個特殊屬性,用來引用Arguments對象,Arguments對象就像數組,可以按照數字獲取傳遞給函數的參數值,但是它并非真正的Array對象。
arguments具有length屬性,
可以使用arguments來檢測調用函數使用了正確數目的實際參數,
注意:arguments并非真正的數組,它是一個Arguments對象,Arguments對象有一個非同尋常的特征,當函數具有命名了的參數時,Arguments對象的數組元素是存放函數參數的局部變量的同義詞。
e.g
function(x){
alert(x); //顯示參數的初始值
arguments[0] = null;//改變數組預算也會改變x
alert(x); //現在顯示為“null”
除了數組元素,Arguments對象還定義了callee屬性,用來引用當前正在執行的函數,這對未命名的函數調用自身非常有用。
e.g
function(x){
if(x<-1)return 1;
return x*arguments.callee(x-1);
}
7.函數的屬性和方法
由于函數是對象,所以它具有數據和方法。
函數的length屬性
函數的屬性length和arguments屬性的length不同,arguments數組的length屬性指定了傳遞給該函數的實際參數數目,并且arguments屬性的length只在函數內部起作用,而函數自身的length屬性它是只讀的,返回的是函數需要的實際參數的數目,并且函數的屬性length函數體的內部和外部都在是有效的。
函數的prototype屬性
每個函數都有一個prototype屬性,它引用的是預定義的原型對象,原型對象在使用new運算符把函數作為構造函數時起作用。
函數自定義屬性
有時候定義全局變量比較亂,可以通過自定義函數屬性來解決
函數的apply()和call()方法
他們的第一個參數都是要調用的函數的對象,在函數體內這一參數是關鍵字this的值,call()的剩余參數是傳遞給要調用的函數的值,apply()的剩余參數是由數組指定的參數。