1. 程式人生 > >js函式、作用域、作用域鏈、閉包、立即執行函式

js函式、作用域、作用域鏈、閉包、立即執行函式

1.函式

定義

1.函式宣告

  • ```java
    function test(){
    函式體
    };
2.函式表示式:
- 命名函式表示式 
- ```java
var fn = function test(){};
  • (匿名)函式表示式
  • var fn = function(){};

組成形式

1.函式名稱
2.引數(形參、實參)
3.返回值

2.作用域

  1. 作用域定義:變數(變數作用域又稱上下文)和函式生效的區域。
  2. [[scope]]:每個js函式都是一個物件,物件中的屬性有些我們可以訪問,有些不可以,這些屬性僅供js引擎存取,[[scope]]就是其中一個,[[scope]]存取了執行期上下文的集合。
  3. 作用域鏈:[[scope]]中鎖儲存的執行期上下文物件的集合,這個集合呈鏈式連結,我們把這種鏈式連結成為作用域鏈。
  4. 執行期上下文:當函式執行時,會建立一個執行期上下文的內部物件。一個執行期上下文定義了一個函式執行時的環境,函式每次執行時對應的執行器上下文都是獨一無二的,所以多次呼叫函式就會建立多個執行器上下文,當函式執行完畢,它所產生的執行期上下文會被銷燬。
  5. 查詢變數:從作用域鏈頂端向下查詢。

3.閉包

  1. 定義:當內部函式被儲存到外部時,將會生成閉包。閉包將會導致作用域鏈不釋放記憶體,導致記憶體洩露。
function a(){
    function b(){
        
    }
    return b;//儲存到外部
}
var demo = a();
demo();
demo();
//a()執行的時候,會定義b,b是在a執行的時候定義,定義的時候會在aAO -- > GO,並且a執行後返回b,b被儲存到外部,故這個之後aAO不會被釋放,從而造成記憶體洩露。
  1. 閉包的作用
  • 實現公有變數
    • eg: 函式累加器
    function add(){
      var count = 0;
      function demo(){
        count++;
        console.log(count);
      }
      return demo;
    }
    var counter = add();
    counter();
    counter();
    counter();
  • 可以做快取(儲存結構)
    多個函式被儲存為一個函式的閉包,它們操作的是同一塊記憶體。
    • eg:eater
     function test(){
      var num = 100;
      function a(){
        num++;
        console.log(num);
      }
      function b(){
        num--;
        console.log(num);
      }
      return [a,b];
    }
    var myArr = test();
    myArr[0]();//101
    myArr[1]();//100
    function eater(){
      var food = "apple";
      var obj = {
        eatFood: function () {
          if(food != ""){
            console.log("eating "  + food);
            food = '';
          }else{
            console.log("it is empty.")
          }
        },
        pushFood: function (myfood) {
          food = myfood;
        }
      }
      return obj;
    }
    
    var person = eater();
    person.eatFood();//eating apple
    person.pushFood("banana");
    person.eatFood();//eating banana
  • 可以實現封裝,屬性私有化
    • eg:Person()
  • 模組化開發,防止汙染全域性變數

4. 立即執行函式

針對初始化功能的函式
立即執行函式執行完就被銷燬。

var num = (function (a,b,c){
    var d = a+b+c;
    return d;
}(1,2,3));

PS:只有表示式才能被執行符號執行。

var test = function(){};
test();//表示式,可以被執行。

+ function (){
    console.log('a');
}();//可以執行,前面加的+讓它變成了表示式。加-也一樣的道理。
function test(){
    var arr = [];
    for(var i = 0;i <10;i++){
        arr[i] = function(){
            document.write(i+" ");
        }
    }
    return arr;
}
var myarr = test();
for(var j = 0;j < 10;+j+){
    myarr[j]();
}//10 10 10 10 10 10 10 10 10 10 
//arr裡面存的十個元素都是函式體,返回arr後被儲存到外部,形成閉包,當myarr = test()執行的時候,arr裡面存了十個函式體,最後退出test的時候i=10.當執行myarr[j]的時候,運用的是test()的執行期上下文,而test()退出時,testAO裡面的i=10.故輸出了10個10.

function test(){
      var arr = [];
      for(var i = 0;i <10;i++){
        (function (j){
            arr[j] = function() {
              document.write(j+" ");
            }
        }(i));
      }
      return arr;
    }

    var myarr = test();
    for(var j = 0;j < 10;j++){
      myarr[j]();
    }//0 1 2 3 4 5 6 7 8 9