函數表達式

一.定義函數html

定義函數的兩種方式:函數聲明和函數表達式閉包

1.函數聲明app

function functionName(arg0,arg1,…){函數

    //函數體this

}prototype

①name屬性:訪問函數的名字3d

alert(funcitonName.name);//」functionName」指針

②函數聲明提高component

在代碼執行以前會先讀取函數聲明(解析器會率先讀取函數聲明)。因此函數聲明能夠放到調用它的語句後邊htm

2.函數表達式:建立函數再賦值給變量

var functionName=function(arg0,arg1,…){

    //函數體

};

①函數聲明要求有名字,但函數表達式不須要。沒有名字的函數表達式叫匿名函數

②沒有函數聲明提高,因此使用前先賦值

sayName(); //出錯

var sayName=function(){

    alert(「liuzhongyi」);

};

③在控制語句中應該使用函數表達式,而不是函數聲明

④使用匿名函數能夠將函數當作值來使用,將函數做爲其餘函數的返回值等

二.遞歸

遞歸函數:一個函數經過名字調用自身

但使用函數名調用自身時,只要函數名變化,遞歸函數將出現問題

①使用arguments.callee來調用自身:是一個指針,指向正在執行的函數

function myFunction(num){
    if(num<=1){
        return 1;
    }else{
        return num * arguments.callee(num-1);
    }
}

②使用函數表達式

var myFunction=(function f(num){
    if(num<1){
        return 1;
    }else{
        return num*f(num-1);
    }
});

即便將myFunction更名,f(num)依然能在函數內使用

三.閉包

閉包:有權訪問另外一個函數做用域中的變量 的函數

建立閉包:在函數內部建立另外一個函數

1.閉包原理

①執行環境和做用域鏈

QQ截圖20131205235823

做用域鏈本質是一個指向變量對象的指針列表,只引用但不實際包含變量對象

當函數執行完畢後,執行環境,做用域鏈及局部變量對象就會銷燬,內存中只保存全局做用域(全局變量對象)

②在一個函數內部定義的匿名函數將外部函數的活動對象(局部變量對象)添加到它的做用域鏈中

這個匿名函數被返回後,它的做用域鏈被初始化爲包含它本身的做用域,包含函數的做用域和全局做用域

函數在執行完畢後,其活動對象也不會銷燬,由於匿名函數的做用域鏈依然在引用這個活動對象

解除匿名函數的引用,活動對象被銷燬 myFunction=null;

2.閉包與變量

閉包只能取得包含函數中任何變量的最後一個值      //沒看懂

3.關於this對象

this對象是與函數運行時的執行環境綁定的,全局函數中this等於window,當函數做爲某個對象的方法調用時,this等於那個對象

var name="window";
var object={
    name:"object",
    getThis:function(){
        return function(){
            return this.name;
        };
    }
};
alert(object.getThis()); //"window" 由於this可以訪問到全局變量中的name變量

this不能指向本身嗎??

var name="window";
var object={
    name:"object",
    getThis:function(){
        return this.name;
    }
};
(object.getThis=object.getThis)(); //"window"
4.內存泄漏
閉包的做用域鏈中保存着一個HTML元素,那麼該元素將沒法被銷燬
由於BOM,COM對象是以COM對象的形式實現的,採用的是引用計數的垃圾收集策略,因爲閉包的存在,HTML元素的引用次數至少是1,因此不能被收回
四.模仿塊級做用域
function outputNumbers(count){
    for(var i=0;i<count;i++){
        alert(i);
    }

var i;
alert(i); //依然計次
}

Java,C中i只會在for循環的語句塊中有定義,循環一結束,變量i就會被銷燬。但JS中沒有塊級做用域,i定義在outputNumbers()的活動對象裏,並且會對後續的再次聲明視而不見

1.私有做用域:用匿名函數模仿塊級做用域

function關鍵字表示函數聲明的開始,將函數聲明轉換成函數表達式,只要給它加上一對圓括號。函數表達式能夠直接做爲值來取代函數名。調用函數就是在後邊加一對圓括號

(function{
    //塊級做用域
})();

匿名函數中定義的任何變量,都會在執行結束時被銷燬

function outputNumbers(count){
    (function(){
        for(var i=0;i<count;i++){
            alert(i);
        }
    })();
alert(i); //出錯
}

好處:

①私有做用域,每一個開發人員均可以定義本身的變量,而不用擔憂擾亂全局做用域

②能夠減小閉包占用的內存,由於沒有指向匿名函數的引用,函數執行完做用域鏈就能夠銷燬

2.私有變量

全部對象屬性都是公有的。(能夠在外部訪問對象屬性)

私有變量:函數的參數,局部變量,函數內部定義的其餘函數。在函數外部不能訪問這些變量

公有方法:能夠經過閉包來實現公有方法,而經過公有方法能夠訪問在包含做用域中定義的變量

特權方法:有權訪問私有變量的方法叫特權方法

自定義類型的特權方法

①在構造函數中定義特權方法

function Person(name){
    this.getName=function(){
        return this.name;
    };
    this.setName=function(value){
        this.name=value;
    };
}
var person1=new Person("liu");
alert(person1.getName());// "liu"
person1.setName("zhong");
alert(person1.getName()); //"zhong"

實現了在構造函數外部訪問了私有變量name

缺點:構造函數的弊端,每一個實例都會建立同一組相同的方法

②靜態私有變量

(function(){
    var name="";
    Person=function(value){   //聲明全局變量,使用函數表達式,由於函數聲明只能建立局部函數
        name=value;
    };
    Person.prototype.getName=function(){
        return name;
    };
    Person.prototype.setName=function(){
        name=value;
    };
})();

var person1=new Person("liu");
alert(person1.getName()); //"liu"
person1.setName("zhong");
alert(person1.getName());

在一個函數上調用私有變量會影響全部實例,每一個實例沒有本身的私有變量

單例的特權方法

①模塊模式

爲單例(只有一個實例的對象)建立私有變量和特權方法

當必須建立一個對象並以某些數據對其初始化,同時還要公開一些可以訪問這些私有數據的方法,就可使用模塊模式

var application=function(){
    //私有變量和函數    
    var components=new Array();
    //初始化
    components.push("liu");
    //公有方法
    return{
        getLength:function(){
            return components.length;    
        }
    }; 
}();

②加強的模塊模式

單例必須是某種類型的實例,同時還必須添加某些屬性和方法對其以加強的狀況

//application對象必須是BaseComponent的實例
var application=function(){
    //私有變量和函數
    var components=new Array();
    //初始化
    components.push(new BaseComponent());
    //建立application的一個局部副本
    var app=new BaseComponent();
    //公共接口
    app.getLength=funtion(){
         return components.length;
    };
    //返回這個副本
    return app;
}();
相關文章
相關標籤/搜索