第七章 函數(shù)表達式(js高級程序設計)

  • 函數(shù)變量提升:在執(zhí)行代碼之前會先讀取函數(shù)聲明贱傀。這就意味著可以把函數(shù)聲明放在調(diào)用它的語句后面乾戏。
  • 函數(shù)聲明:
say()
function say(){

}
  • 函數(shù)表達式
fun ();//error 函數(shù)表達式不存在函數(shù)變量提升
var fun = function(){
  //這個function是匿名函數(shù)
}

遞歸

  • 使用arguments.callee()實現(xiàn)遞歸粪躬。在編寫遞歸函數(shù)時挖炬,使用 arguments.callee 總比使用函數(shù)名更保險传泊。
function factorial(num){ 
 if (num <= 1){ 
 return 1; 
 } else { 
 return num * arguments.callee(num-1); 
 } 
} 
  • 命名函數(shù)表達式的形式創(chuàng)建(在嚴格模式中arguments.callee會報錯)
var factorial = (function f(num){ 
 if (num <= 1){ 
 return 1; 
 } else { 
 return num * f(num-1); 
 } 
}); //即使是修改了factorial變量名函數(shù)內(nèi)部也能調(diào)用到f()命名函數(shù)

閉包

  • 閉包是指有權訪問另一個函數(shù)作用域中的變量的函數(shù)

  • 捋一下一般函數(shù)的一生:

    1. 當創(chuàng)建一個函數(shù)時雪情,會生成一個預先包含全局變量對象(變量對象包括作用域鏈上的所有對象遵岩,全局對象永遠在變量對象上,而局部環(huán)境的變量對象只在函數(shù)執(zhí)行過程中存在)作用域鏈旺罢,存放在函數(shù)的[[Scope]]屬性中
    2. 當調(diào)用函數(shù)執(zhí)行時旷余,函數(shù)會創(chuàng)建執(zhí)行環(huán)境绢记。首先他會吸收[[Scope]]屬性作為執(zhí)行作用域鏈,隨后再將arguments組成的活動對象推入執(zhí)行環(huán)境作用域鏈的前端正卧。
    3. 當函數(shù)執(zhí)行完畢蠢熄,局部活動對象銷毀,全局活動對象保存在內(nèi)存中


      一般函數(shù)的執(zhí)行環(huán)境
  • 捋一下閉包函數(shù)的一生:
    首先用父函數(shù)和匿名函數(shù)來表示外層函數(shù)和返回的內(nèi)層函數(shù)

    1. 當調(diào)用執(zhí)行父函數(shù)創(chuàng)建匿名函數(shù)后炉旷,即使父函數(shù)已經(jīng)執(zhí)行完畢签孔,但是其活動對象不會被銷毀,因為他被匿名函數(shù)引用
    2. 匿名函數(shù)執(zhí)行時窘行,會吸收父函數(shù)和全局變量對象作為執(zhí)行作用域鏈饥追,隨后再將自己局部變量和arguments組成的活動對象推入作用域鏈前端
      所以匿名函數(shù)的作用域鏈是:
      argument和局部變量組成的活動對象
      父函數(shù)的活動對象
      全局變量對象


      父函數(shù)和匿名函數(shù)執(zhí)行環(huán)境
  • 閉包會攜帶包含它的函數(shù)的作用域,因此會比其他函數(shù)占用更多的內(nèi)存罐盔。

閉包與變量

  • 閉包只能取得包含函數(shù)中任何變量的最后一個值

  • 閉包父函數(shù)的活動對象只會保留父函數(shù)執(zhí)行完畢后的一次但绕。舉個栗子:父函數(shù)執(zhí)行 a=1 a=2 a=3,執(zhí)行完畢后a=3,保存給內(nèi)部匿名函數(shù)的活動對象的a就是等于3惶看。所有返回的匿名函數(shù)都是指向相同作用域下的那個a

  function createFunctions() {
    debugger
    var result = new Array();
    for (var i = 0; i < 10; i++) {
      result[i] = function () {
        return i;
      };
    }
    i = 2 //將i重新賦值為2捏顺,則返回結果都是2
    return result;
  }
  const a = createFunctions()
  console.log(a[0]())//2
  console.log(a[5]())//2
  • 當createFunctions執(zhí)行時,父函數(shù)創(chuàng)建i變量纬黎,i隨著程序執(zhí)行變成0幅骄,變成1,變成2本今。拆座。。變成10冠息,變成2挪凑。當createFunctions完全執(zhí)行完畢后,才會將自己的活動變量交給匿名函數(shù)铐达,此時交出去的i是2a场!瓮孙!唐断,所以返回的所有匿名函數(shù)得到的i都是2!杭抠!
  • 解決方法:
    1. 返回匿名自執(zhí)行函數(shù)脸甘,匿名自執(zhí)行函數(shù)再返回閉包函數(shù),匿名自治性函數(shù)傳參給閉包函數(shù)返回偏灿。
    2. 將var改成let丹诀,每個for循環(huán)都是不同的作用域,返回的不再是同一個i

關于this對象

  • this 對象是在運行時基于函數(shù)的執(zhí)行環(huán)境綁定的。
    目前知道的this指向
  1. 全局下指向window
  2. 對象中函數(shù)執(zhí)行對象
  3. 匿名閉包函數(shù)的this指向全局window(每個函數(shù)在被調(diào)用時都會自動取得兩個特殊變量:this 和 arguments铆遭。內(nèi)部函數(shù)在搜索這兩個變量時硝桩,只會搜索到其活動對象為止,因此永遠不可能直接訪問外部函數(shù)中的這兩個變量)
  • 獲得父函數(shù)this的方法枚荣,將父函數(shù)this賦值給變量傳遞

閉包帶來的內(nèi)存泄露

  • 閉包會導致父函數(shù)局部變量一直保存在內(nèi)存中碗脊,因為閉包函數(shù)一直保持著對他的引用
  • 怎么解決?
    1. 將局部變量中需要用到的值取出來引用橄妆,例如const age = obj.age
    2. 將父函數(shù)的局部變量變?yōu)閚ull obj=null(為什么都沒有引用obj還不會被垃圾回收呢衙伶?因為閉包函數(shù)會引用所有父函數(shù)的活動對象
function assignHandler(){ 
 var element = document.getElementById("someElement"); 
 var id = element.id; 
 
 element.onclick = function(){ 
 alert(id); 
 }; 
 
 element = null; 
} 

模仿塊級作用域

  • 在匿名函數(shù)中定義的任何變量,都會在執(zhí)行結束時被銷毀
function outputNumbers(count){ 
 (function () { 
   for (var i=0; i < count; i++){ 
     alert(i); 
   } 
 })(); 
 
 alert(i); //導致一個錯誤害碾!
} 
  • 這種技術經(jīng)常在全局作用域中被用在函數(shù)外部矢劲,從而限制向全局作用域中添加過多的變量和函數(shù)。
  • 這種做法可以減少閉包占用的內(nèi)存問題慌随,因為沒有指向匿名函數(shù)的引用芬沉。只要函數(shù)執(zhí)行完畢,就可以立即銷毀其作用域鏈了儒陨。

私有變量(閉包還可以用在對象創(chuàng)建私有變量)

  • 私有變量:函數(shù)中固定的變量(函數(shù)參數(shù)和函數(shù)的局部變量)
  • 特權方法:能訪問到私有變量的方法
    1. 使用閉包花嘶,匿名函數(shù)返回父函數(shù)中的局部變量
    2. 構造函數(shù)中,通過get(),set()返回私有變量屬性

靜態(tài)私有屬性:在私有作用域中用原型返回私有屬性

模塊模式:如果必須創(chuàng)建一個對象并以某些數(shù)據(jù)對其進行初始化蹦漠,同時還要公開一些能夠訪問這些私有數(shù)據(jù)的方法,那么就可以使用模塊模式车海。和閉包差不多笛园,就是返回了個對象

  var application = function () {
    //私有變量和函數(shù)
    var components = new Array();
    //初始化
    components.push(new BaseComponent());
    //公共
    return {
      getComponentCount: function () {
        return components.length;
      },
      registerComponent: function (component) {
        if (typeof component == "object") {
          components.push(component);
        }
      }
    };
  }();

增強的模塊模式

  • 單例必須是某種類型的實例,同時還必須添加某些屬性和(或)方法對其加以增強的情況(就是返回了一個對象侍芝,該對象又是某個構造函數(shù)的實例)
  var application = function () {
    //私有變量和函數(shù)
    var components = new Array();
    //初始化
    components.push(new BaseComponent());
    //創(chuàng)建 application 的一個局部副本
    var app = new BaseComponent();
    //公共接口
    app.getComponentCount = function () {
      return components.length;
    };
    app.registerComponent = function (component) {
      if (typeof component == "object") {
        components.push(component);
      }
    };
    //返回這個副本
    return app;
  }();
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末研铆,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子州叠,更是在濱河造成了極大的恐慌棵红,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件咧栗,死亡現(xiàn)場離奇詭異逆甜,居然都是意外死亡,警方通過查閱死者的電腦和手機致板,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門交煞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人斟或,你說我怎么就攤上這事素征。” “怎么了?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵御毅,是天一觀的道長根欧。 經(jīng)常有香客問我,道長端蛆,這世上最難降的妖魔是什么凤粗? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮欺税,結果婚禮上侈沪,老公的妹妹穿的比我還像新娘。我一直安慰自己晚凿,他們只是感情好亭罪,可當我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著歼秽,像睡著了一般应役。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上燥筷,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天箩祥,我揣著相機與錄音,去河邊找鬼肆氓。 笑死袍祖,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的谢揪。 我是一名探鬼主播蕉陋,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼拨扶!你這毒婦竟也來了凳鬓?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤患民,失蹤者是張志新(化名)和其女友劉穎缩举,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體匹颤,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡仅孩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了惋嚎。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片杠氢。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖另伍,靈堂內(nèi)的尸體忽然破棺而出鼻百,到底是詐尸還是另有隱情绞旅,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布温艇,位于F島的核電站因悲,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏勺爱。R本人自食惡果不足惜晃琳,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望琐鲁。 院中可真熱鬧卫旱,春花似錦、人聲如沸围段。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽奈泪。三九已至适贸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間涝桅,已是汗流浹背拜姿。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留冯遂,地道東北人蕊肥。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像蛤肌,于是被迫代替她去往敵國和親晴埂。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,515評論 2 359