<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                #第十四章匿名函數與閉包 講師:_無腦碼農(張磊)_ 博客:http://www.h5code.com 課程內容: [TOC] * * * * * >匿名函數就是沒有名字的函數,閉包是可訪問一個函數作用域里變量的函數。聲明:本節內容需要有面向對象和少量設計模式基礎,否則無法聽懂. ###1.>匿名函數 ~~~ //普通函數 function box() { //函數名是box return 'Zhang'; } ~~~ ~~~ //匿名函數 function () { //匿名函數,會報錯 return 'Zhang'; } ~~~ ~~~ //通過表達式自我執行 (function box() { //封裝成表達式 alert('Zhang'); })(); //()表示執行函數,并且傳參 ~~~ ~~~ //把匿名函數賦值給變量 var box = function () { //將匿名函數賦給變量 return 'Zhang'; }; alert(box()); //調用方式和函數調用相似 ~~~ ~~~ //函數里的匿名函數 function box () { return function () { //函數里的匿名函數,產生閉包 return 'Zhang'; } } alert(box()()); //調用匿名函數 ~~~ ###2.>閉包 >閉包是指有權訪問另一個函數作用域中的變量的函數,創建閉包的常見的方式,就是在一個函數內部創建另一個函數,通過另一個函數訪問這個函數的局部變量。 ~~~ //通過閉包可以返回局部變量 function box() { var user = 'Zhang'; return function () { //通過匿名函數返回box()局部變量 return user; }; } alert(box()()); //通過box()()來直接調用匿名函數返回值 var b = box(); alert(b()); //另一種調用匿名函數返回值 ~~~ >使用閉包有一個優點,也是它的缺點:就是可以把局部變量駐留在內存中,可以避免使用全局變量。(全局變量污染導致應用程序不可預測性,每個模塊都可調用必將引來災難,所以推薦使用私有的,封裝的局部變量)。 ~~~ //通過全局變量來累加 var age = 100; //全局變量 function box() { age ++; //模塊級可以調用全局變量,進行累加 } box(); //執行函數,累加了 alert(age); //輸出全局變量 ~~~ ~~~ //通過局部變量無法實現累加 function box() { var age = 100; age ++; //累加 return age; } alert(box()); //101 alert(box()); //101,無法實現,因為又被初始化了 ~~~ ~~~ //通過閉包可以實現局部變量的累加 function box() { var age = 100; return function () { age ++; return age; } } var b = box(); //獲得函數 alert(b()); //調用匿名函數 alert(b()); //第二次調用匿名函數,實現累加 ~~~ *PS:由于閉包里作用域返回的局部變量資源不會被立刻銷毀回收,所以可能會占用更多的內存。過度使用閉包會導致性能下降,建議在非常有必要的時候才使用閉包。* >作用域鏈的機制導致一個問題,在循環中里的匿名函數取得的任何變量都是最后一個值。 ~~~ //循環里包含匿名函數 function box() { var arr = []; for (var i = 0; i < 5; i++) { arr[i] = function () { return i; }; } return arr; } var b = box(); //得到函數數組 alert(b.length); //得到函數集合長度 for (var i = 0; i < b.length; i++) { alert(b[i]()); //輸出每個函數的值,都是最后一個值 } ~~~ >上面的例子輸出的結果都是5,也就是循環后得到的最大的i 值。因為b[i]調用的是匿名函數,匿名函數并沒有自我執行,等到調用的時候,box()已執行完畢,i 早已變成5,所以最終的結果就是5 個5。 ~~~ //循環里包含匿名函數-改1,自我執行匿名函數 function box() { var arr = []; for (var i = 0; i < 5; i++) { arr[i] = (function (num) { //自我執行 return num; })(i); //并且傳參 } return arr; } var b = box(); for (var i = 0; i < b.length; i++) { alert(b[i]); //這里返回的是數組,直接打印即可 } ~~~ >改1 中,我們讓匿名函數進行自我執行,導致最終返回給a[i]的是數組而不是函數了。最終導致b[0]-b[4]中保留了0,1,2,3,4 的值。 ~~~ //循環里包含匿名函數-改2,匿名函數下再做個匿名函數 function box() { var arr = []; for (var i = 0; i < 5; i++) { arr[i] = (function (num) { return function () { //直接返回值,改2 變成返回函數 return num; //原理和改1 一樣 } })(i); } return arr; } var b = box(); for (var i = 0; i < b.length; i++) { alert(b[i]()); //這里通過b[i]()函數調用即可 } ~~~ >改1 和改2 中,我們通過匿名函數自我執行,立即把結果賦值給a[i]。每一個i,是調用方通過按值傳遞的,所以最終返回的都是指定的遞增的i。而不是box()函數里的i。 >關于this 對象在閉包中使用this對象也可能會導致一些問題,this對象是在運行時基于函數的執行環境綁定的,如果this在全局范圍就是window,如果在對象內部就指向這個對象。而閉包卻在運行時指向window 的,因為閉包并不屬于這個對象的屬性或方法。 ~~~ var user = 'The Window'; var obj = { user : 'The Object', getUserFunction : function () { return function () { //閉包不屬于obj,里面的this 指向window return this.user; }; } }; alert(obj.getUserFunction()()); //The window //可以強制指向某個對象 alert(obj.getUserFunction().call(obj)); //The Object //也可以從上一個作用域中得到對象 getUserFunction : function () { var that = this; //從對象的方法里得對象 return function () { return that.user; }; } ~~~ **內存泄漏** >由于IE 的JScript 對象和DOM對象使用不同的垃圾收集方式,因此閉包在IE中會導致一些問題。就是內存泄漏的問題,也就是無法銷毀駐留在內存中的元素。以下代碼有兩個知識點還沒有學習到,一個是DOM,一個是事件。 ~~~ function box() { var oDiv = document.getElementById('oDiv'); //oDiv 用完之后一直駐留在內存 oDiv.onclick = function () { alert(oDiv.innerHTML); //這里用oDiv 導致內存泄漏 }; } box(); ~~~ >那么在最后應該將oDiv 解除引用來避免內存泄漏。 ~~~ function box() { var oDiv = document.getElementById('oDiv'); var text = oDiv.innerHTML; oDiv.onclick = function () { alert(text); }; oDiv = null; //解除引用 } ~~~ *PS:如果并沒有使用解除引用,那么需要等到瀏覽器關閉才得以釋放。* **模仿塊級作用域** >JavaScript 沒有塊級作用域的概念。 ~~~ function box(count) { for (var i=0; i<count; i++) {} alert(i); //i 不會因為離開了for 塊就失效 } box(2); function box(count) { for (var i=0; i<count; i++) {} var i; //就算重新聲明,也不會前面的值 alert(i); } box(2); ~~~ >以上兩個例子,說明JavaScript 沒有塊級語句的作用域,if () {} for () {}等沒有作用域,如果有,出了這個范圍i 就應該被銷毀了。就算重新聲明同一個變量也不會改變它的值。JavaScript 不會提醒你是否多次聲明了同一個變量;遇到這種情況,它只會對后續的聲明視而不見(如果初始化了,當然還會執行的)。使用模仿塊級作用域可避免這個問題。 ~~~ //模仿塊級作用域(私有作用域) (function () { //這里是塊級作用域 })(); //使用塊級作用域(私有作用域)改寫 function box(count) { (function () { for (var i = 0; i<count; i++) {} })(); alert(i); //報錯,無法訪問 } box(2); ~~~ >使用了塊級作用域(私有作用域)后,匿名函數中定義的任何變量,都會在執行結束時被銷毀。這種技術經常在全局作用域中被用在函數外部,從而限制向全局作用域中添加過多的變量和函數。一般來說,我們都應該盡可能少向全局作用域中添加變量和函數。在大型項目中,多人開發的時候,過多的全局變量和函數很容易導致命名沖突,引起災難性的后果。如果采用塊級作用域(私有作用域),每個開發者既可以使用自己的變量,又不必擔心搞亂全局作用域。 ~~~ (function () { var box = [1,2,3,4]; alert(box); //box 出來就不認識了 })(); ~~~ >在全局作用域中使用塊級作用域可以減少閉包占用的內存問題,因為沒有指向匿名函數 的引用。只要函數執行完畢,就可以立即銷毀其作用域鏈了。 **私有變量** >JavaScript 沒有私有屬性的概念;所有的對象屬性都是公有的。不過,卻有一個私有變 量的概念。任何在函數中定義的變量,都可以認為是私有變量,因為不能在函數的外部訪問 這些變量。 ~~~ function box() { var age = 100; //私有變量,外部無法訪問 } ~~~ >而通過函數內部創建一個閉包,那么閉包通過自己的作用域鏈也可以訪問這些變量。而 利用這一點,可以創建用于訪問私有變量的公有方法。 ~~~ function Box() { var age = 100; //私有變量 function run() { //私有函數 return '運行中...'; } this.get = function () { //對外公共的特權方法 return age + run(); }; } var box = new Box(); alert(box.get()); ~~~ >可以通過構造方法傳參來訪問私有變量。 ~~~ function Person(value) { var user = value; //這句其實可以省略 this.getUser = function () { return user; }; this.setUser = function (value) { user = value; }; } ~~~ >但是對象的方法,在多次調用的時候,會多次創建。可以使用靜態私有變量來避免這個問題。 **靜態私有變量** >通過塊級作用域(私有作用域)中定義私有變量或函數,同樣可以創建對外公共的特權方 法。 ~~~ (function () { var age = 100; function run() { return '運行中...'; } Box = function () {}; //構造方法 Box.prototype.go = function () { //原型方法 return age + run(); }; })(); var box = new Box(); alert(box.go()); ~~~ >上面的對象聲明,采用的是Box = function () {} 而不是function Box() {} 因為如果用后面這種,就變成私有函數了,無法在全局訪問到了,所以使用了前面這種。 ~~~ (function () { var user = ''; Person = function (value) { user = value; }; Person.prototype.getUser = function () { return user; }; Person.prototype.setUser = function (value) { user = value; } })(); ~~~ >使用了prototype 導致方法共享了,而user 也就變成靜態屬性了。(所謂靜態屬性,即共享于不同對象中的屬性)。 **模塊模式** >之前采用的都是構造函數的方式來創建私有變量和特權方法。那么對象字面量方式就采用模塊模式來創建。 ~~~ var box = { //字面量對象,也是單例對象 age : 100, //這是公有屬性,將要改成私有 run : function () { //這時公有函數,將要改成私有 return '運行中...'; }; }; 私有化變量和函數: var box = function () { var age = 100; function run() { return '運行中...'; } return { //直接返回對象 go : function () { return age + run(); } }; }(); ~~~ >上面的直接返回對象的例子,也可以這么寫: ~~~ var box = function () { var age = 100; function run() { return '運行中...'; } var obj = { //創建字面量對象 go : function () { return age + run(); } }; return obj; //返回這個對象 }(); ~~~ >字面量的對象聲明,其實在設計模式中可以看作是一種單例模式,所謂單例模式,就是永遠保持對象的一個實例。 >增強的模塊模式,這種模式適合返回自定義對象,也就是構造函數。 ~~~ function Desk() {}; var box = function () { var age = 100; function run() { return '運行中...'; } var desk = new Desk(); //可以實例化特定的對象 desk.go = function () { return age + run(); }; return desk; }(); alert(box.go()); ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看