javascript基礎-函數

函數表達式和函數聲明

  • 函數聲明:function 函數名稱 (參數:可選){ 函數體 }javascript

  • 函數表達式:function 函數名稱(可選)(參數:可選){ 函數體 }
    函數聲明只能出如今程序或函數體內。從語法上講,它們不能出如今Block(塊)({ ... })中。表達式和聲明存在着十分微妙的差異,函數聲明會在任何表達式被解析和求值以前先被解析和求值。不管變量在函數內何處聲明,在代碼執行階段,變量都會在提到函數開始執行以前被聲明,而函數聲明發生在更早的階段。java

var foo;
    if (true) {
       foo = function (){ console.log(1); };
    }else {
       foo = function (){ console.log(2); };
    }
    foo(); // 1

先聲明foo變量,在代碼處理的第一步,按照程序執行順序,建立函數表達式並賦值給foo。
    if (true) {
       function foo(){ console.log(1); }
    }else {
       function foo(){ console.log(2); }
    }
    foo(); // 2

基於Gecko的瀏覽器 //1
函數聲明在代碼處理的第一步。function foo(){ console.log(2); }會覆蓋前面的操做。

  alert(sum(10,10));    //20
  function sum(num1, num2){
      return num1 + num2;
  }        
  alert(sum(10,10));    //causes an error
  var sum = function(num1, num2){
      return num1 + num2;
  };
  //變量sum的聲明仍是放在第一步處理
  • 命名函數表達式:var bar = function foo(){};須要注意的地方:這個名字只在新定義的函數做用域內有效(IE9之前版本的IE版本中)。命名函數表達式方便調試。瀏覽器

var f = function foo(){
      return typeof foo; // foo是在內部做用域內有效
    };
    // foo在外部用因而不可見的
    typeof foo; // "undefined"       IE5-IE8中 " function"
    f(); // "function"

調用模式

  1. 方法調用模式
    當一個函數保存爲對象的一個屬性時,咱們稱它爲方法。當一個方法被調用的時候,this被綁定到該對象。若是調用表達式包含一個提取屬性的動做xxx.xxx,那麼它就是被當作方法來調用的。安全

  2. 函數調用模式
    this被綁定到全局對象。閉包

  3. 構造器調用模式
    this被綁定到建立的新對象。app

  4. apply調用模式
    apply容許咱們選擇this的值,方法接受兩個參數,第一個是要綁定this的值,第二個是參數數值。第一個參數爲null,undefined將會被替換成全局對象。嚴格模式use strict的時候不會被替換。函數

做用域

不少現代語言都推薦延遲聲明變量,js中推薦在函數體的頂部聲明函數中可能用到的全部變量。
JScript的Bugthis

例1:函數表達式的標示符泄露到外部做用域
typeof g; // "function"
var f = function g(){};
IE9已經修復

例2:將命名函數表達式同時看成函數聲明和函數表達式
typeof g; // "function"
var f = function g(){};

函數聲明會優先於任何表達式被解析,上面的例子展現的是JScript其實是把命名函數表達式當成函數聲明瞭,由於它在實際聲明以前就解析了ges5

匿名函數

匿名函數中this 通常指向window對象
XXXX.prototype.__XXX = function(){} 不是匿名函數prototype

閉包

在編寫遞歸函數時,使用arguments.callee (可是es5嚴格模式下會報錯)比使用函數名安全。
函數中的變量對象就是活動對象。
不管何時在函數內部訪問一個變量時,就會從做用域鏈中搜索相應變量。通常來說,當函數執行完畢後局部活動對象將被銷燬。可是閉包狀況有所不一樣。

在createComparisonFunction()函數內部定義的匿名函數的做用域鏈中,不包含外部函數createComparisonFunction()的活動對象。
var compare = createComparisonFunction("name");
var result = compare(obj1, obj2);
createComparisonFunction()在執行完畢之後,其執行環境的做用域鏈被銷燬,可是其活動對象不會被銷燬,由於匿名函數的做用域鏈中仍然引用着這個活動對象,直到匿名函數執行完畢後,才一塊兒被銷燬。閉包會攜帶包含他的函數的做用域,佔用內存較多。

閉包與變量

閉包只能取得包含函數中變量最後保存的值。
function createFunctions() {
  var result = new Array();
  for (var i = 0; i < 10; i++) {
      result[i] = function() {
          return i;
      };
  }  
  return result;
}
var funcs = createFunctions();
//every function outputs 10
for (var i = 0; i < funcs.length; i++) {
  document.write(funcs[i]() + "<br />");
}
使用匿名函數再添加一層外部函數,多了一個閉包使原來的閉包知足條件
function createFunctions() {
  var result = new Array();
  for (var i = 0; i < 10; i++) {
      result[i] = function(num) {
          return function() {
              return num;
          };
      }(i);
  }
  return result;
}
var funcs = createFunctions();
//every function outputs 10
for (var i = 0; i < funcs.length; i++) {
  document.write(funcs[i]() + "<br />");
}

用閉包保存狀態

閉包直接能夠引用傳入的參數,利用這些被lock住的傳入參數,自執行函數表達式能夠有效地保存狀態。

// 這個代碼是錯誤的,由於變量i歷來就沒背locked住
// 相反,當循環執行之後,咱們在點擊的時候i纔得到數值
// 由於這個時候i操真正得到值
// 因此說不管點擊那個鏈接,最終顯示的都是I am link #10(若是有10個a元素的話)
var elems = document.getElementsByTagName('a');
for (var i = 0; i < elems.length; i++) {
  elems[i].addEventListener('click', function (e) {
      e.preventDefault();
      alert('I am link #' + i);
  }, 'false');

}
// 這個是能夠用的,由於他在自執行函數表達式閉包內部
// i的值做爲locked的索引存在,在循環執行結束之後,儘管最後i的值變成了a元素總數(例如10)
// 但閉包內部的lockedInIndex值是沒有改變,由於他已經執行完畢了
// 因此當點擊鏈接的時候,結果是正確的

var elems = document.getElementsByTagName('a');
for (var i = 0; i < elems.length; i++) {
  (function (lockedInIndex) {
      elems[i].addEventListener('click', function (e) {
          e.preventDefault();
          alert('I am link #' + lockedInIndex);
      }, 'false');
  })(i);
}

// 你也能夠像下面這樣應用,在處理函數那裏使用自執行函數表達式
// 而不是在addEventListener外部
// 可是相對來講,上面的代碼更具可讀性
var elems = document.getElementsByTagName('a');
for (var i = 0; i < elems.length; i++) {
  elems[i].addEventListener('click', (function (lockedInIndex) {
      return function (e) {
          e.preventDefault();
          alert('I am link #' + lockedInIndex);
      };
  })(i), 'false');
}

自執行函數表達式

利用了閉包的特性,能夠避免全局變量

javascript語法中()內部不能包含語句,只能包含表達式。
(function () { /* code */ } ()); // 推薦使用這個
相關文章
相關標籤/搜索