JS之函數表達式

  度過一個愉快短暫的週末,又能夠開始學習了!我愛學習,學習令人進步。今天學習函數表達式,着重學習下閉包函數。html

函數表達式前端

   能夠在定義的函數聲明以前調用它,可是不能在定義函數表達式以前調用它 c#

/**
 * 理解函數聲明和函數表達式的區別,學習拉姆達(Lambda)表達式
 */
functionName(a);
aFuncton(a);//錯誤 function fuctionName(arg){};//函數聲明 var aFunction=function (arg) {};//函數表達式(匿名函數) /* 函數聲明:在執行代碼以前會先讀取函數聲明,函數聲明能夠放在調用它的語句後面。
 Lambda表達式:建立匿名函數的一種方法,=>來表示
 運算符右邊的表達式對運算符左邊指定的參數執行操做
*/
var x=3,
   fun= 

x=>{returnx*x;};//lambda表達式

遞歸:在函數內部調用本身數組

  

/**
 * 借用arguments.callee和使用函數命名錶達式實現遞歸
 */
//遞歸函數
function factorial(num){
    if(num<=1){ return 1; }else{ return num*factorial(num-1); } }; var anotherFactorial=factorial; factorial=null; alert(anotherFactorial(4));//出錯,factorial值發生變化。 //解決方案:1.非嚴格模式下 function factorial(num){ if(num<=1){ return 1; }else{ return num*arguments.callee(num-1); } }; //2.命名函數表達式 var factorial=(function f(num){ if(num<=1){ return 1; }else { return num * f(num - 1); } });

 

 閉包:可以訪問另外一個函數做用域中的變量的函數。閉包

  做用域鏈:本質上是一個指向變量對象的指針列表函數

    建立函數時,會建立一個預先包含全局變量對象的的做用域鏈,這個做用域鏈被保存在內部的[[Scope]]屬性中,調用函數時建立一個執行環境,而後複製[[Scope]]屬性中的對象構建起執行環境的做用域鏈,而後有一個函數的活動對象被建立並推入執行環境做用域鏈的前端。學習

   在另外一個函數內部定義的函數會將包含函數(即外部函數)的活動對象添加到它的做用域鏈中   this

function createComparisonFunction(propertyName) {
    return function(object1,object2){ var value1=object1[propertyName]; var value2=object2[propertyName]; if(value1<value2){return -1;} else if(value1>value2){return 1;} else{return 0;} }; } //建立函數 var compareNames=createComparisonFunction('name'); //調用函數 var result=compareNames({name:'趙雲'},{name:'馬超'}); //解除對匿名函數的引用,以便釋放內存 compareNames=null;

  做用域鏈能夠想象成一個列表,裏面的函數建立時候內部建立它,這個列表中,最上面的spa

  上面的例子中,有兩個做用域鏈,createComparisonFunction和匿名函數function(object1,object2)的做用域鏈分別是A和B。匿名函數從compareName()被返回後,B包含全局變量對象、createComparisonFunction函數的活動對象和匿名函數的活動對象的引用,createComparisonFunction函數執行完畢A被銷燬,可是它的活動對象被B引用,雖然這樣能夠在全局環境中訪問外部這個函數的變量了,但這個外部函數的活動對象已然存在。因此調用函數結束後要解除對匿名函數的引用。設計

    

function a(){
     var result=[]; for (var i=0;i<10;i++){ result[i]=function () { return i;}; } }

    上面的例子中,最後result數組中每一個值都是10! 由於i是a函數活動對象中的變量,每一個內部函數做用域鏈中都有a的活動對象,因此引用的是同一個i,a函數返回後i=10。

解決方案:使用當即執行函數

 1 function a() {
 2     var result = []; 3 for (var i = 0; i < 10; i++) { 4 result[i] = function (num) { 5 return function () { 6 return num; 7  } 8  } 9 return result; 10  } 11 }

 

  在做用域中聲明的變量,可能會被其餘人不當心用同名的變量給覆蓋掉,做用域鏈的特性,用匿名函數做爲一個容器,容器內部能夠訪問外部的變量,而外部環境不能訪問容器內部的變量,因此( function(){…} )()內部定義的變量不會和外部的變量發生衝突,至關於命名空間。

  閉包中使用this對象

    this對象是在運行時基於函數的執行環境綁定的:全局函數,this等於window,而當函數被最爲某個對象的方法調用時,this就是那個對象。因爲匿名環境具備全局性,它的this一般指向window.

 1 var name='Window';
 2 var  object={ 3 name:'object', 4 getName:function(){ 5 return function () { 6 return this.name 7  } 8  } 9 };; 10 console.log(object.getName()) //Window

  例子中getName方返回一個匿名函數,這個匿名函數返回this.name,調用內部匿名函數的時候,你不函數在搜索this和arguments兩個變量時,只會搜索到活動對象爲止。

解決方案:

var name='Window';
var  object={ name:'object', getName:function(){ var that=this; return function () { return that.name; } } }; console.log(object.getName());

 

  閉包函數會致使內存泄露,在垃圾清理的引用計數模式中,若是有閉包函數做用域鏈中有html元素,則該元素的引用至少一直是1,所以它所佔用的內存不會被回收,所以要吧該元素的賦值變量設爲null;

    模仿塊級做用域:

(function(){})();//把函數聲明轉爲函數表達式

當即調用了一個匿名函數

在一個由不少開發人員共同參與的大型應用程序中,過多的全局變量和函數容易致使命名衝突,經過建立私有做用域解決。

    私有變量

  任何函數中定義的變量,能夠認爲是私有變量。包括函數的參數,局部變量和函數內部定義跌其它函數。

訪問私有變量方法:1構造函數中建立閉包

  靜態私有變量:利用原型。

 

重點:模塊模式

  對象字面量:實際是單例(只有一個實例的對象)。模塊模式就是爲單例建立私有變量和特權方法。

  

 1 var singleton=function(){
 2     //私有變量和私有函數
 3     var privateVaribale=10; 4 function privateFunction(){ 5 return false; 6  } 7 return{ 8 publicProperty:true; 9  publicMethod:funciont(){ 10 privateVaribale++; 11 return privateFunction(); 12  } 13  }; 14 }();

  這個模塊模式使用了一個返回對象的匿名函數。在這個匿名函數內部,首先定義了私有變量和函數,有一個對象字面量做爲函數的值返回,所以它的公有方法有權訪問私有變量和函數。從本質上來講,這個對象字面量定義的是單例的公共接口。這種模式在須要對單例進行某些初始化,同時又須要維護其私有變量時是很是有用的。

  模塊模式用來設計一個加載器什麼的頗有用,專門寫一篇來分析。

相關文章
相關標籤/搜索