<font id="zqva1"></font>
<rt id="zqva1"></rt>
  • <tt id="zqva1"></tt>
    <cite id="zqva1"></cite>

    <cite id="zqva1"><noscript id="zqva1"></noscript></cite>
      <rp id="zqva1"><meter id="zqva1"></meter></rp>

        <cite id="zqva1"></cite>
          <b id="zqva1"></b>
          <rp id="zqva1"></rp>
          <cite id="zqva1"></cite>

          <rt id="zqva1"></rt>

        1. <rp id="zqva1"></rp>

          指令式編程 VS 聲明式編程

          時間:?2017-12-11閱讀:?913標簽:?指令

          概括地說,我們可以有兩種編寫代碼的方式:指令式和聲明式。

          我們可以定義如下:

          • 指令式編程:告訴機器該如何做,并得到自己想要的結果。

          • 聲明式編程:告訴機器您想得到什么,讓機器自己計算該如何做。


          指令式編程和聲明式編程的例子

          舉一個簡單的例子,假設我們想讓數組中的每個值變為原來的2倍。

          指令式編程的代碼可以如下:

          var numbers = [1,2,3,4,5]
          var doubled = []
          for(var i = 0; i<numbers.length; i++) {
            var newNumber = numbers[i] * 2
            doubled.push(newNumber)
          }
          console.log(doubled) //=>[2,4,6,8,10]


          我們遍歷整個數組,取出每個元素,乘以2,然后把新值放到新數組中,直到完成。

          一種聲明式的編程方式可以使用Array.map,如下:

          var numbers = [1,2,3,4,5]
          var doubled = numbers.map(function(n) {
            return n * 2
          })
          console.log(doubled) //=>[2,4,6,8,10]
          

          map根據舊數組返回新的數組,在這個例子中,通過把舊數組中的元素傳入到map (function(n) { return n*2 }中,返回一個新數組,新數組的每個值都是相對應的舊數組的值的2倍。

          map函數的作用是抽象出遍歷數組的過程,讓我們更關注于我們想得到什么。注意,我們傳入到map中的函數是純凈的。不能有任何副作用(改變其他額外的狀態),它只是拿到一個數,并把它變成2倍。

          對于數組,這里還有其他一些常見的聲明式抽象函數。比如說,為了對數組中所有的元素求和,我們可以這么做:

          var numbers = [1,2,3,4,5]
          var total = 0
          
          for(var i = 0; i < numbers.length; i++) {
            total += numbers[i]
          }
          console.log(total) //=> 15


          或者我們可以使用聲明式函數reduce:

          var numbers = [1,2,3,4,5]
          
          var total = numbers.reduce(function(sum, n) {
            return sum + n
          }, 0);
          console.log(total) //=> 15


          reduce利用給定的函數將數組遍歷計算出一個值。它將這個函數應用到數組中的每個元素。在每次調用中,第一個參數(例子中的sum)是前一個元素調用函數后得出的結果,第二個參數(n)是當前元素。所以,在這個例子中,每一步,都把當前數組元素n加到sum中,這樣,最后我們就能得到整個數組的和。

          同樣,reduce為我們抽象了循環遍歷和狀態管理方面的事情,給了我們遍歷數組計算出一個值的通用方法。我們需要做的就是明確我們想要什么。


          很奇怪?

          我保證,如果您之前沒見過map或者reduce,您一定會感覺到奇怪。作為程序員,我們總是很習慣指定如何讓事情發生,“遍歷數組”,“如果怎么樣然后怎么樣”,“用新值更新這個變量”。既然我們已經知道如何告訴機器該怎么做,為什么還要學習這個看起來有點奇怪的抽象呢?

          在許多情況下,指令式代碼是好的。當我們編寫業務邏輯時,我們通常不得不編寫大部分必需的代碼,因為在我們的業務邏輯中不存在更通用的抽象。

          但是如果我們花時間去學習(或構建!)聲明式的抽象方法,在編寫代碼時,我們就可以使用一些強大的快捷方式。首先,我們通常會寫得越來越少,這是一個速見成效的勝利。然后,我們也可以在一個更高的層次思考問題,站在云端思考我們想要發生什么,而不是陷在泥里思考如何使它發生。


          SQL

          您可能沒有意識到,但是在SQL中,您已經使用過聲明式編程了。

          您可以把SQL看作一種用于處理數據集的聲明式查詢語言。您是否用SQL寫過整個應用?可能沒有。但是對于處理相關聯的數據集,它會非常強大。

          做一個查詢:

          SELECT * from dogs
          INNER JOIN owners
          WHERE dogs.owner_id = owners.id
          

          想象一下您用指令式編程來寫這段邏輯

          //dogs = [{name: 'Fido', owner_id: 1}, {...}, ... ]
          //owners = [{id: 1, name: 'Bob'}, {...}, ...]
          
          var dogsWithOwners = []
          var dog, owner
          
          for(var di=0; di < dogs.length; di++) {
            dog = dogs[di]
          
            for(var oi=0; oi < owners.length; oi++) {
              owner = owners[oi]
              if (owner && dog.owner_id == owner.id) {
                dogsWithOwners.push({
                  dog: dog,
                  owner: owner
                })
              }
            }}
          }


          我并不是說SQL很容易理解,或者當您第一次看到時就很輕松地明白它,但是相比于那段復雜的代碼,它已經簡潔很多了。

          但是它不僅更簡短而且更容易閱讀,SQL還給了我們許多其他好處。因為我們已經抽象了具體的實現方法,我們可以只關注我們想要什么,然后讓數據庫優化具體實現步驟。

          如果我們沒有使用它,我們自己的代碼將會很慢,因為我們必須要為列表中的每只dog遍歷整個owners數組。

          但是在SQL代碼的例子中,我們可以讓數據庫來自己實現如何返回給我們正確的結果。如果使用索引有意義(假設我們已經建立了),數據庫就會這么做,這會提升很大的性能。如果此次查詢在一秒前就執行過,就可以直接從緩存中讀取。通過放手讓計算機自己決定實現方式,我們只需要稍微改變一下認知,就可以得到巨大的好處。


          d3.js

          另外一個能體現出聲明式編程好處的地方在用戶界面、圖表和動畫。

          編寫用戶界面是一件很困難的事。因為我們有用戶交互,想要做好用戶交互,我們通常會有很多的狀態管理和指令式代碼,其實這些都可以被抽象出來,但通常并沒有。

          一個很好的聲明式抽象的例子是d3.js。通過使用JavaScript和SVG(大部分),d3這個庫可以幫我們創建交互式的,帶動畫的可視化數據。

          第一次(第五次,甚至第十次)您看到或嘗試寫d3代碼,您可能都會頭痛。就像SQL一樣,d3幾乎封裝了所有您可能用到的處理可視化數據的方法,讓您只關注您想得到什么。

          這里有一個例子(我建議大家看一下這個例子,了解下上下文)。這個d3圖表是根據data數組中的每個對象畫一個圓。為了展示發生了什么,我們每秒鐘加一個圓。

          有趣的代碼是:

          //var data = [{x: 5, y: 10}, {x: 20, y: 5}]
          var circles = svg.selectAll('circle')
                              .data(data)
          
          circles.enter().append('circle')
                     .attr('cx', function(d) { return d.x })
                     .attr('cy', function(d) { return d.y })
                     .attr('r', 0)
                  .transition().duration(500)
                    .attr('r', 5)


          沒有必要弄清這里究竟發生了什么(不管怎樣,你都需要一段時間才能清醒過來),但要點是這樣的:

          首先我們選取所有的circlesvg(初始的時候沒有)。然后給它們綁定一些數據。

          D3持續追蹤哪個數據點被綁定到圖表中哪個圓上。所以開始的時候我們有兩個數據點,但是沒有圓;然后我們可以使用.enter()方法來獲取已經“進入”的數據點。對于這些點,我們想對應地將一個圓加入到圖表中,以數據的x和y為圓心,初始半徑為0,但是0.5s后漸變到半徑為5。


          這為什么有趣?

          再來看一下代碼,并思考我們是否描述了我們想要什么樣的可視化圖表,或者是否怎樣來畫?您會發現,幾乎沒有怎樣畫的代碼出現。我們只是描述了我們想要什么:

          > 我想要把這個數據畫成圓,圓心由數據指定。并且如果有新的圓,就加進來,且半徑要有動畫。

          這很神奇,我們沒有寫一個循環,也沒有寫狀態管理。編寫圖表通常是困難和麻煩的,但是d3已經為我們做了大部分封裝,我們只需要明確我們想要什么即可。

          現在d3.js易懂了嗎?并沒有,它肯定要花一段時間來學習。并且您大部分要學習的是放棄指定事情如何發生,而是要學習如何明確您想要什么。

          剛開始的時候,這很困難,但是經過幾個小時后,神奇的事情發生了——您會越來越有效率。通過封裝具體實現方式,d3.js真正地讓您關注您想看到什么,并且這也是當您實現可視化時只需要關注的。它把您從繁瑣的細節中解放出來,讓您以一個更高的水平思考問題,打開了創造的可能性。


          最后

          聲明式編程允許我們描述我們想要的,讓底層軟件/計算機等來處理具體如何實現。

          正如所見,很多時候,這可以讓我們在寫代碼方面得到提高,不僅是更少的代碼行數,或者性能,而且高抽象的編碼方式使我們能更關注于我們想要什么,這正是我們作為問題解決者真正該關心的。

          問題是,過去我們已經習慣于指令式編程。它使我們感覺舒服和自然,甚至強大(能夠控制它是怎么發生的),不肯將具體實現方式交給我們看不到或者不理解的程序。

          有時候,編寫具體實現方式是可以的。如果我們需要微調代碼來提高性能,我們可能需要更細節地指明如何實現。或者對于業務代碼,本身就沒有什么可以抽象封裝的地方,我們就得編寫指令式代碼。

          但是,我們可以(并且應該)經常尋找聲明性的方法來編寫代碼,如果找不到,我們應該構建它們。這在開始的時候會很困難嗎?是的,幾乎可以肯定!但正如我們看到的SQL和d3.js,長期收益是巨大的!

          站長推薦

          1.阿里云: 本站目前使用的是阿里云主機,安全/可靠/穩定。點擊領取2000元代金券、了解最新阿里云產品的各種優惠活動點擊進入

          2.騰訊云: 提供云服務器、云數據庫、云存儲、視頻與CDN、域名等服務。騰訊云各類產品的最新活動,優惠券領取點擊進入

          3.廣告聯盟: 整理了目前主流的廣告聯盟平臺,如果你有流量,可以作為參考選擇適合你的平臺點擊進入

          鏈接: http://www.modern-decoration.com.cn/article/detial/238

          一個指令為各大vue組件庫的table組件加上動態編輯功能

          在現代的vue組件庫上實現表格編輯其實不難,它們大都提供了作用域插槽,可以在插槽內插入input組件來實現。但這樣做有個弊端,太重了!在幾十上百行的表格內鋪滿input卡頓幾乎不可避免,而且也很難做到美觀。

          vue中自定義v-model指令

          v-model是vue實現數據雙向綁定最好的一個指令, v-model本質上不過是語法糖,它負責監聽用戶的輸入事件以更新數據,當你修改頁面的時候 v-model 自動去更新數據層 (model),當你修改數據的時候v-model自動去更新視圖層 (view)

          Vue的基礎指令

          通過添加v-bind:標簽屬性來控制標簽的屬性,設置后自動查詢Vue里面的數據,通常簡寫成:標簽屬性,也可以傳入對象,通過對象的值來控制是否為真

          Vue自定義指令:實現文字溢出顯示、鼠標移入浮層展示全部

          將文字放到一個容器中,將容器的樣式(主要是有關字體的樣式)都設置為當前元素的樣式,然后獲取容器的寬,也就是文字的寬,如果文字的寬度超過了當前元素的寬度,則給溢出隱藏的css樣式

          手寫vue中v-bind:style效果的自定義指令

          以 v- 為前綴,然后加上自己定義好的名字組成的一個指令就是自定義指令。為什么要有自定義指令呢?在有些時候,你仍然需要對普通的DOM元素進行底層的操作,這個時候就可以用到自定義指令

          這15個Vue指令,讓你的項目開發爽到爆

          V-Hotkey這個指令可以給組件綁定一個或多個快捷鍵。你想要通過按下 Escape 鍵后隱藏某個組件,按住 Control 和回車鍵再顯示它嗎?小菜一碟:你想要點擊外部區域關掉某個組件嗎?用這個指令可以輕松實現。

          常用docker指令

          docker 我的常用指令:從docker倉庫下載鏡像到本地、列出本地所有鏡像、查看正在運行的容器、列出所有創建的容器、停止、查看日志

          理解vue自定義指令

          除了核心功能默認的內置指令(v-model和v-show),vue也允許注冊自定義指令。注意,在Vue2.0中,代碼復用和抽象的主要形式是組件,但是在有些情況下,我們需要對普通的DOM元素進行底層操作,這時候就需要我們用到自定義指令

          vue自定義指令:防抖與節流

          防抖:觸發事件后,一段時間內沒有再次觸發則執行,若此時間段內再次觸發重新延時!節流一段時間內首次觸發時立即執行,此時間段內再次觸發,不會執行!

          Docker常用指令

          主要總結一些docker常用指令,方便大家查詢使用:運行主機一般運行主機時會-it組合使用,用以建立一個可在終端交互的容器,比如:docker run -it --name local_nginx nginx:latest /bin/bash

          內容以共享、參考、研究為目的,不存在任何商業目的。其版權屬原作者所有,如有侵權或違規,請與小編聯系!情況屬實本人將予以刪除!

          文章投稿關于web前端網站點搜索站長推薦網站地圖站長QQ:522607023

          小程序專欄: 土味情話心理測試腦筋急轉彎幽默笑話段子句子語錄成語大全運營推廣

          国产精品高清视频免费 - 视频 - 在线观看 - 影视资讯 - 唯爱网