第7章 函數(shù)表達式

//不要這么做

if( condition ){
      function sayHi(){
           alert('Hello!');
      }
} else {
      function sayHi(){
           alert('Yo!');
      }
}

因為不同瀏覽器對上面代碼理解不同航闺,ie不管condition是否為真,都會執(zhí)行alert('Yo!')

//可以這么做

var sayHi;

if( condition ){
    sayHi = function(){
          alert('Hello!');
    }
} else {
    sayHi = function(){
          alert('Yo!');
    }
}

7.1 遞歸

經(jīng)典遞歸函數(shù):

function factorial(num){
  if( num <= 1 ){
        return 1;
  } else {
    return num * factorial(num-1);
  }
}

可是,遇到下面情況缸夹,會出問題:

var another = factorial;

factorial = null;

console.log(another(2))  //出錯

因為在調(diào)用another時候术陶,factorial已經(jīng)不是一個函數(shù)了凑懂。

可以使用 arguments.callee 解決問題:
注意:arguments.callee 是一個指向正在執(zhí)行的函數(shù)的指針。

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

7.2 閉包

閉包:指有權(quán)訪問另一個函數(shù)作用域中的變量的函數(shù)梧宫。

創(chuàng)建閉包的常見方式接谨,就是在一個函數(shù)內(nèi)部創(chuàng)建另一個函數(shù)。

函數(shù)被調(diào)用時塘匣,都會發(fā)生些什么脓豪?如何創(chuàng)建作用域鏈,作用域鏈有什么作用馆铁?

來看這一段代碼:

function compare(value1, value2){
   if( value1 < value2 ){
       return -1;
   } else if ( value1 > value2 ) {
       return 1;
   } else {
       return 0;
   }
}

var result = compare(5, 10);

以上代碼中跑揉,當調(diào)用了compare()時,會創(chuàng)建一個作用域鏈埠巨,其中历谍,arguments、value1辣垒、value2處于作用域鏈的第一位望侈,全局執(zhí)行環(huán)境的變量(包含result和compare)則處于第二位。

很顯然勋桶,作用域鏈本質(zhì)上是一個指向變量對象的指針列表脱衙,它只引用但不實際包含變量對象侥猬。

再來看一個函數(shù):

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 compare = createComparisonFunction('name');
var result = compare({ name: 'jack' }, { name: 'mack'} )

注意:在另一個函數(shù)內(nèi)部定義的函數(shù)會將包含函數(shù)(即外部函數(shù))的活動對象添加到自己的作用域鏈中。因此捐韩,
在createComparisonFunction() 函數(shù)內(nèi)部定義的匿名函數(shù)的作用域鏈中退唠,實際上將會包含外部函數(shù)createComparisonFunction()的活動對象。

 其實荤胁,就是說瞧预,對于閉包,它的作用域鏈不僅僅是自己內(nèi)部仅政,還包括自己的外部垢油。

接著說上面的函數(shù),

在匿名函數(shù)從createComparisonFunction()中被返回后圆丹,它的作用域鏈被初始化為包含createComparisonFunction()函數(shù)的活動對象和全局變量對象滩愁。
這樣,匿名函數(shù)就可以訪問在createComparisonFunction()中定義的所有變量辫封。

更為重要的是硝枉,createComparisonFunction()函數(shù)在執(zhí)行完畢后,其活動對象也不會被銷毀秸讹,因為匿名函數(shù)的作用域鏈仍然在引用這個活動對象檀咙。
換句話說,當createComparisonFunction() 函數(shù)返回后璃诀,其執(zhí)行環(huán)境的作用域鏈會被銷毀弧可,但它的活動對象仍然會留在內(nèi)存中,直到匿名函數(shù)被銷毀劣欢,

createComparisonFunction() 函數(shù)的活動對象才會被銷毀棕诵。

例如:

//創(chuàng)建函數(shù)
var compareNames = createComparisonFunction('name');

//調(diào)用函數(shù)
var result = compareNames({ name: 'jack' }, { name: 'mack'} );

//解除對匿名函數(shù)的引用(以便釋放內(nèi)存)
compareNames = null;

就是說,創(chuàng)建一個匿名函數(shù)后凿将,除非手動設(shè)置其為null來進行銷毀釋放內(nèi)存校套,否則,這個匿名函數(shù)以及其引用的外部變量依然會存在于內(nèi)存中牧抵。

建議:由于閉包會攜帶包含它的函數(shù)的作用域笛匙,因此會比其他函數(shù)占用更多的內(nèi)存。過度使用閉包可能會導(dǎo)致內(nèi)存占用過多犀变,因此妹孙,我們建議讀者只在絕對必要時再考慮使用閉包。

7.2.1 閉包與變量

作用域鏈的這種配置機制引出了一個值得注意的副作用获枝,即閉包只能取得包含函數(shù)中任何變量的最后一個值蠢正。別忘了,閉包所保存的是整個變量對象省店,而不是某個特殊的變量嚣崭。

function create(){
  var result = [];

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

console.log(create())

這個函數(shù)會返回一個數(shù)組笨触,但是每個函數(shù)都返回10。 因為每個函數(shù)的作用域鏈中都保存著 create() 函數(shù)的活動對象雹舀,所以它們引用的都是同一個變量 i芦劣。

怎么樣讓每個函數(shù)返回自己?我們可以創(chuàng)建另一個匿名函數(shù)強制讓閉包的行為符合預(yù)期葱跋。

function create(){
  var result = [];

  for(var i = 0; i < 10; i++){
    result[i] = function(num) {
      return function(){
        return num;
      }
    }
    console.log(result[i])
  }
  return result;
}
console.log(create())

7.2.2 關(guān)于this對象

我們知道持寄,this對象是在運行時基于函數(shù)的執(zhí)行環(huán)境綁定的:在全局函數(shù)中,this等于window娱俺,而當函數(shù)被作為某個對象的方法調(diào)用時,this等于那個對象废麻。

重點:不過荠卷,匿名函數(shù)的執(zhí)行環(huán)境具有全局性,因此其this對象通常指向window烛愧。

但是油宜,有時候,由于編寫閉包的方式不同怜姿,這一點可能不會那么明顯

var name = 'the window';

var object = {
  name: 'my object',

  getNameFunc: function(){
    return function() {
            return this.name;
    }
  }
}

console.log(object.getNameFunc()()); ==> the window

如何讓閉包訪問object中的name呢慎冤?可以這么做:

var name = 'the window';

var object = {
  name: 'my object',

  getNameFunc: function(){
    var that = this;
    return function() {
      return that.name;
    }
  }
}

console.log(object.getNameFunc()());

7.3 模仿塊級作用域

由于JS沒用塊級作用域,即意味著在塊語句內(nèi)部定義的變量沧卢,全局環(huán)境中都可以訪問得到蚁堤。

比如:

function outputNumbers(count){
   for( var i = 0; i < count; i++ ){
        alert(i)
   }
   alert(i) ==> 5
}

alert(i) ==> 報錯

outputNumbers(5);

由于沒有塊級作用域,在for循環(huán)之內(nèi)的i變量但狭,被定義在了其外部函數(shù)中披诗。而在全局環(huán)境中查找不到i是因為js有函數(shù)作用域。

雖然js沒有塊級作用域立磁,但是我們可以通過匿名函數(shù)來模仿塊級作用域呈队。

function outputNumbers(count){
   (function(){
       for(var i = 0; i < count; i++){
           alert(i);
       }
   })();
   alert(i)  ==> 報錯。i只能在for循環(huán)中訪問得到
}

在匿名函數(shù)中定義的任何變量唱歧,都會在執(zhí)行結(jié)束時被銷毀宪摧。因此,i只能在循環(huán)中使用颅崩,使用后即被銷毀几于。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市挨摸,隨后出現(xiàn)的幾起案子孩革,更是在濱河造成了極大的恐慌,老刑警劉巖得运,帶你破解...
    沈念sama閱讀 211,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件膝蜈,死亡現(xiàn)場離奇詭異锅移,居然都是意外死亡,警方通過查閱死者的電腦和手機饱搏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評論 3 385
  • 文/潘曉璐 我一進店門非剃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人推沸,你說我怎么就攤上這事备绽。” “怎么了鬓催?”我有些...
    開封第一講書人閱讀 157,435評論 0 348
  • 文/不壞的土叔 我叫張陵肺素,是天一觀的道長。 經(jīng)常有香客問我宇驾,道長倍靡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,509評論 1 284
  • 正文 為了忘掉前任课舍,我火速辦了婚禮塌西,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘筝尾。我一直安慰自己捡需,他們只是感情好,可當我...
    茶點故事閱讀 65,611評論 6 386
  • 文/花漫 我一把揭開白布筹淫。 她就那樣靜靜地躺著站辉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪贸街。 梳的紋絲不亂的頭發(fā)上庵寞,一...
    開封第一講書人閱讀 49,837評論 1 290
  • 那天,我揣著相機與錄音薛匪,去河邊找鬼捐川。 笑死,一個胖子當著我的面吹牛逸尖,可吹牛的內(nèi)容都是我干的古沥。 我是一名探鬼主播,決...
    沈念sama閱讀 38,987評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼娇跟,長吁一口氣:“原來是場噩夢啊……” “哼岩齿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起苞俘,我...
    開封第一講書人閱讀 37,730評論 0 267
  • 序言:老撾萬榮一對情侶失蹤盹沈,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后吃谣,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體乞封,經(jīng)...
    沈念sama閱讀 44,194評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡做裙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,525評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了肃晚。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锚贱。...
    茶點故事閱讀 38,664評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖关串,靈堂內(nèi)的尸體忽然破棺而出拧廊,到底是詐尸還是另有隱情,我是刑警寧澤晋修,帶...
    沈念sama閱讀 34,334評論 4 330
  • 正文 年R本政府宣布吧碾,位于F島的核電站,受9級特大地震影響飞蚓,放射性物質(zhì)發(fā)生泄漏滤港。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,944評論 3 313
  • 文/蒙蒙 一趴拧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧山叮,春花似錦著榴、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,764評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至锐借,卻和暖如春问麸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背钞翔。 一陣腳步聲響...
    開封第一講書人閱讀 31,997評論 1 266
  • 我被黑心中介騙來泰國打工严卖, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人布轿。 一個月前我還...
    沈念sama閱讀 46,389評論 2 360
  • 正文 我出身青樓哮笆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親汰扭。 傳聞我的和親對象是個殘疾皇子稠肘,可洞房花燭夜當晚...
    茶點故事閱讀 43,554評論 2 349

推薦閱讀更多精彩內(nèi)容

  • 1、定義函數(shù)的兩種方式:1)函數(shù)聲明:存在函數(shù)聲明提升2)函數(shù)表達式:使用前必須先賦值萝毛;匿名函數(shù)(拉姆達函數(shù)) 2...
    94小輝閱讀 289評論 0 0
  • 定義函數(shù)的方式有兩種:函數(shù)聲明和函數(shù)表達式项阴。 函數(shù)聲明的一個重要特征就是函數(shù)聲明提升,意思是在執(zhí)行代碼前會先讀取函...
    oWSQo閱讀 661評論 0 0
  • 常規(guī)方式定義函數(shù) 定義函數(shù)有兩種方式笆包,第一種方式為常規(guī)聲明方式环揽,該方式下函數(shù)可以先使用略荡,后聲明,即"函數(shù)聲明提升"...
    勤勞的悄悄閱讀 254評論 0 0
  • 包管理 檢查.deb包內(nèi)容 dpkg-deb --info arping_2.11-1_armhf.debdpkg...
    bluexiii閱讀 342評論 0 1
  • 錐子臉、帶美瞳跨扮、指甲貼亮片序无;隆起的胸部、水蛇腰以及黑絲緊繃的長腿衡创。這是很多外圍女的標準樣貌帝嗡。應(yīng)該說,通過科技(整容...
    羊年小少閱讀 1,162評論 2 20