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

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                [TOC] # 第 2 章: 一等公民的函數 ## 快速概覽 當我們說函數是“一等公民”的時候,我們實際上說的是它們和其他對象都一樣...所以就是普通公民(坐經濟艙的人?)。函數真沒什么特殊的,你可以像對待任何其他數據類型一樣對待它們——把它們存在數組里,當作參數傳遞,賦值給變量...等等。 這是 JavaScript 語言的基礎概念,不過還是值得提一提的,因為在 Github 上隨便一搜就能看到對這個概念的集體無視,或者也可能是無知。我們來看一個杜撰的例子: ```js var hi = function(name){ return "Hi " + name; }; var greeting = function(name) { return hi(name); }; ``` 這里 `greeting` 指向的那個把 `hi` 包了一層的包裹函數完全是多余的。為什么?因為 JavaScript 的函數是*可調用*的,當 `hi` 后面緊跟 `()` 的時候就會運行并返回一個值;如果沒有 `()`,`hi` 就簡單地返回存到這個變量里的函數。我們來確認一下: ```js hi; // function(name){ // return "Hi " + name // } hi("jonas"); // "Hi jonas" ``` `greeting` 只不過是轉了個身然后以相同的參數調用了 `hi` 函數而已,因此我們可以這么寫: ```js var greeting = hi; greeting("times"); // "Hi times" ``` 換句話說,`hi` 已經是個接受一個參數的函數了,為何要再定義一個額外的包裹函數,而它僅僅是用這個相同的參數調用 `hi`?完全沒有道理。這就像在大夏天里穿上你最厚的大衣,只是為了跟熱空氣過不去,然后吃上個冰棍。真是脫褲子放屁多此一舉。 用一個函數把另一個函數包起來,目的僅僅是延遲執行,真的是非常糟糕的編程習慣。(稍后我將告訴你原因,跟可維護性密切相關。) 充分理解這個問題對讀懂本書后面的內容至關重要,所以我們再來看幾個例子。以下代碼都來自 npm 上的模塊包: ```js // 太傻了 var getServerStuff = function(callback){ return ajaxCall(function(json){ return callback(json); }); }; // 這才像樣 var getServerStuff = ajaxCall; ``` 世界上到處都充斥著這樣的垃圾 ajax 代碼。以下是上述兩種寫法等價的原因: ```js // 這行 return ajaxCall(function(json){ return callback(json); }); // 等價于這行 return ajaxCall(callback); // 那么,重構下 getServerStuff var getServerStuff = function(callback){ return ajaxCall(callback); }; // ...就等于 var getServerStuff = ajaxCall; // <-- 看,沒有括號哦 ``` 各位,以上才是寫函數的正確方式。一會兒再告訴你為何我對此如此執著。 ```js var BlogController = (function() { var index = function(posts) { return Views.index(posts); }; var show = function(post) { return Views.show(post); }; var create = function(attrs) { return Db.create(attrs); }; var update = function(post, attrs) { return Db.update(post, attrs); }; var destroy = function(post) { return Db.destroy(post); }; return {index: index, show: show, create: create, update: update, destroy: destroy}; })(); ``` 這個可笑的控制器(controller)99% 的代碼都是垃圾。我們可以把它重寫成這樣: ```js var BlogController = {index: Views.index, show: Views.show, create: Db.create, update: Db.update, destroy: Db.destroy}; ``` ...或者直接全部刪掉,因為它的作用僅僅就是把視圖(Views)和數據庫(Db)打包在一起而已。 ## 為何鐘愛一等公民? 好了,現在我們來看看鐘愛一等公民的原因是什么。前面 `getServerStuff` 和 `BlogController` 兩個例子你也都看到了,雖說添加一些沒有實際用處的間接層實現起來很容易,但這樣做除了徒增代碼量,提高維護和檢索代碼的成本外,沒有任何用處。 另外,如果一個函數被不必要地包裹起來了,而且發生了改動,那么包裹它的那個函數也要做相應的變更。 ```js httpGet('/post/2', function(json){ return renderPost(json); }); ``` 如果 `httpGet` 要改成可以拋出一個可能出現的 `err` 異常,那我們還要回過頭去把“膠水”函數也改了。 ```js // 把整個應用里的所有 httpGet 調用都改成這樣,可以傳遞 err 參數。 httpGet('/post/2', function(json, err){ return renderPost(json, err); }); ``` 寫成一等公民函數的形式,要做的改動將會少得多: ```js httpGet('/post/2', renderPost); // renderPost 將會在 httpGet 中調用,想要多少參數都行 ``` 除了刪除不必要的函數,正確地為參數命名也必不可少。當然命名不是什么大問題,但還是有可能存在一些不當的命名,尤其隨著代碼量的增長以及需求的變更,這種可能性也會增加。 項目中常見的一種造成混淆的原因是,針對同一個概念使用不同的命名。還有通用代碼的問題。比如,下面這兩個函數做的事情一模一樣,但后一個就顯得更加通用,可重用性也更高: ```js // 只針對當前的博客 var validArticles = function(articles) { return articles.filter(function(article){ return article !== null && article !== undefined; }); }; // 對未來的項目友好太多 var compact = function(xs) { return xs.filter(function(x) { return x !== null && x !== undefined; }); }; ``` 在命名的時候,我們特別容易把自己限定在特定的數據上(本例中是 `articles`)。這種現象很常見,也是重復造輪子的一大原因。 有一點我必須得指出,你一定要非常小心 `this` 值,別讓它反咬你一口,這一點與面向對象代碼類似。如果一個底層函數使用了 `this`,而且是以一等公民的方式被調用的,那你就等著 JS 這個蹩腳的抽象概念發怒吧。 ```js var fs = require('fs'); // 太可怕了 fs.readFile('freaky_friday.txt', Db.save); // 好一點點 fs.readFile('freaky_friday.txt', Db.save.bind(Db)); ``` 把 Db 綁定(bind)到它自己身上以后,你就可以隨心所欲地調用它的原型鏈式垃圾代碼了。`this` 就像一塊臟尿布,我盡可能地避免使用它,因為在函數式編程中根本用不到它。然而,在使用其他的類庫時,你卻不得不向這個瘋狂的世界低頭。 也有人反駁說 `this` 能提高執行速度。如果你是這種對速度吹毛求疵的人,那你還是合上這本書吧。要是沒法退貨退款,也許你可以去換一本更入門的書來讀。 至此,我們才準備好繼續后面的章節。 [第 3 章: 純函數的好處](ch3.md)
                  <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>

                              哎呀哎呀视频在线观看