在ECMAScript中,Function(函數)類型其實是對象。每一個函數都是Function類型的實例,並且都與其餘引用類型同樣具備屬性和方法。因爲函數是對象,所以函數名實際上也是一個指向函數對象的指針。
一.函數的聲明方式
1.普通的函數聲明算法
function box(num1,num2) { //普通函數的聲明方式 return num1+num2; } alert(box(1,2)); //返回3
2.使用變量初始化函數數組
var box=function(num1,num2) { //使用變量初始化函數 return num1+num2; }; alert(box(1,2)); //返回3
3.使用Function構造函數app
var box=new Function('num1','num2','return num1+num2'); //使用new的構造函數來聲明函數 alert(box(1,2)); //返回3 alert(typeof box); //字符串仍是function
注意:第三種方式咱們不推薦,由於這種語法會致使解析兩次代碼(第一次解析常規ECMAScript代碼,第二次是解析傳入構造函數中的字符串),從而影響性能。但咱們能夠經過這種語法來理解"函數是對象,函數名是指針"的概念。函數
二.做爲值的函數
1.不是做爲函數來傳遞的,而是做爲函數的返回值來傳遞的性能
function box(sum,num){ return sum+num; //把num做爲跟sum相加的數字 } function sum(num){ return num+10; } var result=box(sum(10),10); //20,10sum(10)這裏傳遞的是函數的返回值,和普通的變量同樣,沒區別 alert(result); //結果是:30
要把函數自己做爲參數傳遞,而不是函數的結果this
function box(sum,num) { return sum(num); //把num做爲參數傳到sum() } function sum(num){ return num+10; } var result=box(sum,10); //這裏sum是一個函數,看成參數傳遞到另一個函數裏,而不是函數的返回值 alert(result); //20
三.函數內部屬性
在函數內部,有兩個特殊的對象:arguments和this。arguments是一個類數組對象,包含着傳入函數中的全部參數,主要用途是保存函數參數。但這個對象還有一個名叫callee的屬性,該屬性是一個指針,指向擁有這個arguments對象的函數。spa
function sum(num) { if (num<=1){ //傳入的num若是小於等於1 return 1; //返回1 } else { return num * sum(num-1); //若是傳入的是4至關於4*3*2*1=24階乘,遞歸 } } alert(sum(4)); //返回24
對於階乘函數通常要用到遞歸算法,因此函數內部必定會調用自身;若是函數名不改變是沒有問題的,但一旦改變函數名,內部的自身調用須要逐一修改。爲了解決這個問題,咱們可使用arguments.callee 來代替。prototype
function box(num) { if (num<=1) { //傳入的num若是小於等於1 return 1; //返回1 } else { return num*arguments.callee(num-1); //使用arguments.callee,調用自身,實現遞歸 } } alert(box(4)); //返回24
函數內部另外一個特殊對象是this,其行爲與Java和C#中的this大體類似。換句話說,this引用的是函數據以執行操做的對象,或者說函數調用語句所處的那個做用域。當在全局做用域中調用函數時,this對象引用的就是window。
window是一個對象,並且是JS裏面最大的對象,是最外圍的對象指針
//打印一下window alert(typeof window); //window是對象,類型是object對象,window表示全局
//打印this alert(this); //[object Window]this目前表示的是window,由於在window的範圍下 alert(typeof this); //this和window如出一轍,因此this就是window
var color='紅色的'; //這裏color就是全局變量,而這個變量又是window的屬性 //alert(window.color); //輸出:紅色的。說明color是window下的屬性 alert(this.color); //輸出:紅色的。同上
因此window.color='紅色的'至關於var color='紅色的';是同樣的code
例1:
window.color = '紅色的'; var box={ color:'藍色的', //這裏的color是box下的屬性,也就是局部變量 sayColor:function(){ alert(this.color); //在打印出:藍色的。這裏this,咱們肯定了是表明的box對象。 } }; alert(this.color); //先打印出:紅色的 box.sayColor();
例2:
window.color='紅色的'; function sayColor() { alert(this.color); //先打印出:紅色的後打印出藍色的、這裏執行的時候是動態的,第一次在window下,第二次在box下 } sayColor(); //這裏調用sayColor,其實範圍仍是在window下 var box = { color : '藍色的' }; box.sayColor = sayColor; //這段代碼至關sayColor:function() box.sayColor(); //這裏執行的是box裏面的this.color,至關於alert(this.color)
四.函數屬性和方法
ECMAScript中的函數是對象,所以函數也有屬性和方法。每一個函數都包含兩個屬性:length和prototype。其中,length屬性表示函數但願接收的命名參數的個數。
function box(name,age){ return name+age; } alert(box.length); //查看傳了幾個屬性:2
對於prototype屬性,它是保存全部實例方法的真正所在,也就是原型。這個屬性,咱們將在面向對象一章詳細介紹。而prototype下有兩個方法:apply()和call(),每一個函數都包含這兩個非繼承而來的方法。這兩個方法的用途都在特定的做用域中調用函數,實際上等於設置函數體內this對象的值。
原函數相加方法:
function box(num1,num2){ return num1+num2; } alert(sayBox(10,10)); //20
經過apply冒充另一個函數:
function box(num1,num2){ return num1+num2; //原函數 } function sum(num1,num2) { //apply和能夠冒充另一個函數(sum能夠冒充box能夠執行box的功能) return box.apply(this,[num1,num2]); //this表示window做用域,[]表示傳遞的參數 } alert(sum(10,10)); //20
經過apply當數組傳遞:
function box(num1,num2) { //原函數 return num1+num2; } function sum2(num1,num2) { return box.apply(this,arguments); //這個能夠當數組傳遞,arguments } alert(sum2(10,10));
call()方法於 apply()方法相同,他們的區別僅僅在於接收參數的方式不一樣。對於call()方法而言,第一個參數是做用域,沒有變化,變化只是其他的參數都是直接傳遞給函數的。
function box(num1,num2) { //原函數 return num1+num2; } function sum(num1,num2) { return box.call(this,num1,num2); //call只是傳遞參數不一樣,其餘和apply同樣 } alert(sum(10,10)); //20
事實上,傳遞參數並非apply()和call()方法真正的用武之地;它們常用的地方是可以擴展函數賴以運行的做用域。
var color='紅色的'; //全局 var box={ //box對象 color:'藍色的' //局部 }; function sayColor(){ alert(this.color); } sayColor(); //全局打印:紅色的 //用call是實現對象冒充,冒充box下,冒充window下 sayColor.call(window); //冒充window:紅色的 sayColor.call(this); //this就是window:紅色的 sayColor.call(box); //冒充box,做用域就在box對象裏面,因此color就是alert(this.color);打印:藍色的
這個例子是以前做用域理解的例子修改而成,咱們能夠發現當咱們使用call(box)方法的時候,sayColor()方法的運行環境已經變成了box對象裏了。使用call()或者apply()來擴充做用域的最大好處,就是對象不須要與方法發生任何耦合關係(耦合,就是互相關聯的意思,擴展和維護會發生連鎖反應)。也就是說,box對象和sayColor()方法之間不會有多餘的關聯操做,好比box.sayColor=sayColor;