之前寫過函數也屬于引用類型,與其他引用類型一樣也是具有屬性和方法。
由于函數是對象,繼承自object,因此函數名實際上是一個指向函數對象的指針。
函數的定義方法:
- 使用函數聲明的語法定義:
function sum(num1,num2)
{
return num1+num2;
}
這種聲明方法,使得sum的類型為function型,這里說過。 - 使用函數表達式定義函數:
var sum=function(num1,num2){
return num1+num2;
}
這種方法,定義了變量sum并將其初始化為一個函數。通過變量sum就可以引用函數,這樣可以通過變量將函數賦值給其他變量使用這一個函數。不用再聲明同功能的函數了。 - 使用Function構造函數:
var sum=new Function("num1","num2","return num1+num2");
不推薦,這種語法會導致解析兩次代碼。一次是常規代碼,依次是字符串。 - 【補充】說一下,第二種方法,由于函數名僅僅是指向函數的指針,所以一個函數可能會有多個名字。
var anothersum=sum;
sum=null;
var s=anothersum(1,2);//3
當sum后面不帶括號的時候,是賦值,即讓anothersum也指向該函數實例。而當將sum置空,即sum不指向該函數實例,我們發現也完全不影響anothersum指向。
function沒有重載
重載是指將函數設置不同的參數個數或類型,當實際調用函數時,根據參數的個數或類型來選擇適合的函數。(我說的白話)
原因
函數名想象為指針后,
function sum(num1,num2)
{
return num1+num2;//+
}
var sum=function(num1,num2){
return num1-num2;//-
};
alert(sum(1,2));//-1
發現第二個函數覆蓋了第一個函數,原因是因為sum被指向了另一個實例化的函數對象。-
彌補
- 當程序想要通過根據參數的個數實現重載時,我們可以借助函數的內部屬性:
arguments
- 當程序想要通過根據參數的個數實現重載時,我們可以借助函數的內部屬性:
在函數內部有兩個而特殊的對象,
this
與arguments
。arguments與函數的參數有關,js函數的參數與其他語言中函數的參數有所不同,js不介意傳遞進來多少個參數,也不在乎傳進來的參數是什么數據類型,這樣一聽,貌似重載沒得救了,因為似乎無論形參設置多少個,都沒關系,調用該函數時肯定會調用他。而實參傳遞多少似乎函數都可以獲得,這就要通過
arguments
啦.-
arguments
其主要用途是用來保存函數參數。
arguments[0]//表示傳遞的第一個元素
arguments[1]//表示傳遞的第二個元素
……//與數組類似,但是并不是Array的實例哦- 可以通過 arguments.length的值來判斷實參的個數。進而可以通過
if
語句來判斷語句的執行情況。 - 需要注意的是,即使形參可有可無,但是,既然提供了這個功能,那么他必然和arguments之間有一定的關系,即二者之中哪一個被修改了,都會影響到對方的值,但是二者并不是指向同一個內存空間。
- arguments這個對象還有一個屬性:callee,該屬性是一個指針,指向擁有arguments對象的函數。
這個屬性有一個經典的作用:看這個函數
function factorial(num){
if(num<=1){
return 1;
}
else{
return numfactorial(num-1);
}
}
alert(factorial(5));//120
這是一個計算階乘的遞歸函數,發現函數內部使用了變量factorial,但是事實上一個實例化的函數對象可以擁有很多個名字,但是這樣寫似乎使得這個遞歸函數只能效力于名字是factorial的啦,
【解決方法】
//將
return numfactorial(num-1);
//替換為
return num*arguments.callee(num-1);
- 可以通過 arguments.length的值來判斷實參的個數。進而可以通過
-
this對象
函數內部的另一個特殊對象,- this是js的一個關鍵字,其的值會跟著環境的不同而不同。
- 但是有一個原則,this指的是調用函數的那個對象,更精準的this引用的是函數據以執行的環境對象。
- 當在網頁全局作用域中調用時,this對象引用的就是window。
caller這個屬性雖然在ECMAScript 3并沒有定義這個屬性,但是這個屬性中保存著調用當前函數的函數的引用。
function outer(){
inner();
}
function inner(){
alert(arguments.callee.caller)
}
outer()//顯示outer函數的源代碼-
函數的屬性和方法
除了前面提到的函數內部的兩個特殊對象,在函數外部,我們還可以通過:函數名.函數的屬性名或方法名的模式調用函數的屬性和方法。- 屬性length
表示每個函數準備接收的命名參數的個數,即形參的個數,區別于內部對象arguments是實參的個數。
function sum(num1,num2,num3)
{
alert(arguments.callee.length);//方法2:內部對象調用
}
sum(1,2)
alert(sum.length);//方法1:函數調用 - 屬性prototype
這個屬性即為原型屬性,在創建自定義類型及實現繼承時,該屬性的作用極為重要。會另寫一篇來細說。
- 屬性length
-
方法apply()與方法call()
這兩個方法是非繼承而來的,所以也就是鼻祖object對象可沒有這兩個方法。這兩個方法的用途都是在特定的作用域中調用函數,實際上設置函數體內this對象的值。等等!this對象的值!
var obj={name:"dudu";}; var ss=function(){alert(this.name)}; obj.showname=ss;
此時ss所指向的函數內部的this的是obj。這個是我們常見的修改this對象值的方法。
js通過為函數提供這兩個方法,也可以實現修改函數this對象的方法- apply方法 有兩個參數,1個是在其中運行函數的作用域,另一個是參數數組。
function sum(num1,num2)
{
return num1+num2;
}
function callsum(num1,num2)
{
// return sum.apply(this,arguments);
return sum.apply(this,[num1,num2]);//效果一樣,數組!!
}
alert(callsum(10,10))//20
callsum里面的this,由于callsum是在全局作用域下被調用,所以this是windows對象,即為sum函數創造一個全局作用域。第二個參數是arguments,即callsum的參數,并將它作為sum 的參數。apply所在的那句代碼翻譯下來就是在全局環境下:sum(10,10);
- call方法,與apply方法的作用一樣,但是接收參數的方式不同,其參數必須逐個例出來
return sum.call(this,num1,num2);
- apply方法 有兩個參數,1個是在其中運行函數的作用域,另一個是參數數組。
- 以上這兩個例子并沒有看出來他們的作用,看下一個例子。
/定義一個屬于兩個對象的屬性red/
window.color='red';
var o={color:"blue"};
/this的值取決于調用他的對象,/
function sayColor(){
alert(this.color);
}
/將作用域設為this,即展示window.color/
sayColor.call(this);//red
sayColor.call(window);//red
/將作用域設為o,即展示o.color/
sayColor.call(o);//blue
使用call()與apply()方法較之前設置this值的方法的好處是對象不需要與方法有任何的關系。上個例子,對象o并沒有將saycolor設置為自己的方法,卻也可以使用這個函數。
- 以上這兩個例子并沒有看出來他們的作用,看下一個例子。
bind方法
window.color='red';
var o={color:"blue"};
/this的值取決于調用他的對象,/
function sayColor(){
alert(this.color);
var objectSayColor=sayColor.bind(o);
objectSayColor();//blue
新創建的函數objectSayColor其this值被綁定了對象o,即使在全局環境下運行,其this值也是對象o。toString()、toLocalString()、valueOf()這三個也是函數的方法,但是其返回值均為函數的代碼,至于代碼格式因瀏覽而異。