<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>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                什么是閉包?可以在自己定義的詞法作用域以外的地方執行,就是閉包。 ``` function foo(){ var a = 2; function bar(){ console.log(a); } return bar; } var baz = foo(); baz(); //2 ``` bar很明顯被執行了,但是它在自己定義的詞法作用域以外的地方執行了。 foo()執行后,期待foo()的整個內部作用域都被銷毀,看起來foo()的內容不會再使用,應當被回收。但是,閉包的神奇之處就在于可以阻止這件事情發生。事實上內部作用域依然存在,所以無法被回收。bar聲明的位置導致bar擁有涵蓋整個foo內部作用域的閉包,它一直在引用著該作用域。正是因為它無法被銷毀,才使得函數可以繼續訪問定義時的詞法作用域。 閉包的常見場景就是在一個函數內的回調函數: ``` function wait(message){ setTimeout(function(){ console.log(message); }, 1000) }; wait('hello') //在1000毫秒后,匿名函數仍然能夠獲取到message的值,這是因為wait的內部作用域不會消失,匿名函數一直擁有對它的引用。 function setupBot(name, selector){ $(selector).click(function(){ console.log(name); }) }; setupBot('qc', DIV); //setupBot執行完后,函數并不會被回收,當你點擊的時候匿名函數仍然能獲得當初的name。 ``` #### 循環與閉包 ``` for(var i = 0; i < 5; i++){ setTimeout(function(){console.log(i)}, 1000); } //結果很明顯是5個6,因為i是被共用的 ``` 如何解決?思路是每次循環時為i創建一個副本來保存當前i的值。立即執行函數會自動創建自己的作用域。 ``` for(var i = 0; i < 5; i++){ (function(){ setTimeout(function(){ console.log(i) }, 1000); })(); } ``` 然而這是不夠的,結果依舊是5個6。立即執行函數內部的作用域是空的,需要為作用域內添加點東西: ``` for(var i = 0; i < 5; i++){ (function(j){ var j = i; setTimeout(function(){ console.log(j) }, 1000); })(); } //也可以寫成 for(var i = 0; i < 5; i++){ (function(j){ setTimeout(function(){ console.log(j) }, 1000); })(i); } ``` 現在好了,每一次迭代時都會通過立即執行函數創建內部作用域保存i的值,在循環結束后,閉包仍然能夠訪問內部作用域的值。 #### let let擁有自動創建作用域的功能: ``` for(let i = 0; i < 5; i++){ setTimeout(function(){console.log(i)}, 1000); } ``` 問題解決! #### 模塊 ``` function module(){ var something = 'cool'; var another = [1, 2, 3]; function doSomething(){ console.log(something); } function doAnother(){ console.log(another); } return { doSomething: doSomething, doAnother: doAnother } } var foo = module(); foo.doSomething(); foo.doAnother(); //函數必須執行,否則無法創建內部作用域和閉包 //該函數返回的是含有對內部函數引用的對象,而不是對內部數據變量引用的對象。 ``` 模塊模式需要具備兩個必要條件 1. 必須有外部的封閉函數,該函數必須至少被調用一次(每調用一次都會創建一個新的模塊)。 2. 封閉函數必須返回至少一個內部函數,這樣內部函數才能在私有作用域中形成閉包,并且可以訪問或者修改私有的狀態。 由此可以看出來,一個擁有函數屬性的對象并不是真正的模塊。 由于module每執行一次都會創建新的模塊實例,當只需要一個實例的時候,可以使用立即執行函數來實現單例模式: ``` var foo = (function module(){ var something = 'cool'; var another = [1, 2, 3]; function doSomething(){ console.log(something); } function doAnother(){ console.log(another); } return { doSomething: doSomething, doAnother: doAnother } })() foo.doSomething(); ``` 模塊的另一個強大的用法是可以修改模塊內的任意東西: ``` var foo = (function(id){ function change(){ api.identify = identify2; } function identify1(){ console.log(id); } function identify2(){ console.log(id.toUpperCase()); } var api = { change: change, identify: identify1 } return api; })('foo'); foo.identify(); //foo foo.change(); foo.identify(); //FOO ``` 由于閉包的存在,整個模塊的作用域會一直存在著,api這個變量永遠不會銷毀。當調用change后,api的identify就由1替換成了2。 #### 現代模塊機制 請認真思考下面的代碼原理 ``` var Module = (function(){ var modules = {}; function define(name, deps, impl){ for(var i = 0; i < deps.length; i++){ deps[i] = modules[deps[i]] } modules[name] = impl.apply(impl, deps); } function get(name){ return modules[name]; } return {define: define, get: get}; })() ``` ``` Module.define("bar", [], function(){ function hello(name){ return name; } return {hello: hello}; }) Module.define("foo", ["bar"], function(bar){ function hi(){ console.log('name is: ' + bar.hello('qc')); } return {hi: hi}; }) ``` ``` var bar = Module.get("bar"); var foo = Module.get("foo"); console.log(bar.hello('mescal')); // mescal foo.hi(); // name is: qc ``` 這種模塊機制是運行時執行的,它的api只有在運行時才被創建,我們可以在運行時修改api,參考identify那個例子。而ES6的模塊機制是基于文件的,它的api就是靜態的,因此錯誤檢查在編譯階段就執行了,而上述代碼的模塊機制的錯誤檢查在運行時才開始。
                  <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>

                              哎呀哎呀视频在线观看