ECMAScript中Function類型

在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;

相關文章
相關標籤/搜索