整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          javaScript-遞歸函數

          javaScript-遞歸函數

          歸函數是一種特殊的函數,遞歸函數允許在函數定義中調用函數本身。考慮對于如下計算:n!=n*(n-1)*(n-2)*...*1

          希望能寫一個簡單的函數完成對n!的求值。觀察上面等式發現:(n-1)!=(n-1)*(n-2)*...*1

          則有如下等式:n!=n*(n-1)!

          注意到等式左邊需要求n的階乘,而等式右邊則是求n-1的階乘。實質都是一個函數,因此可將求階乘的函數定義:

          <script type="text/javascript">
           //定義求階乘的函數
           var factorial=function(n)
           {
           //只有n的類型是數值,才執行函數
           if(typeof(n)=="number")
           {
           //當n等于1時,直接返回1
           if(n==1)
           {
           return 1;
           }
           //當n不等于1時,通過遞歸返回值
           else
           {
           return n*factorial(n-1);
           }
           }
           //當參數不是數值時,直接返回
           else
           {
           alert("參數類型不對!");
           }
           }
           //調用階乘函數
           alert(factorial(5));
           </script>
          

          結果:


          上面程序中粗體字代碼再次調用了factorial()函數,這就是在函數里調用函數本身,也就是所謂的遞歸。上面程序執行的結果是120,可以正常求出5的階乘。注意到程序中判斷參數時,先判斷參數n是否為數值,而且要求n大于0才會繼續運算。事實上,這個函數不僅要求n為數值,而且必須是大于0的整數,否則函數不僅不能得到正確結果,而且將產生內存溢出。

          對于上面遞歸函數,當n為一個大于0的整數,例如5時,5的階乘為4的階乘和5的乘積;同理,4的階乘為3的階乘和4的乘積……依次類推,直到最后1的階乘,代碼中已經寫明:當n=1時,返回值為1。然后反算回去,所有的值都變成已知的。反過來,當n為負數,例如-1時,-1的階乘為-1與-2的階乘的乘積,-2的階乘為-2和-3的階乘的乘積……這將一直追溯到負無窮大,沒有盡頭,導致程序溢出。

          可見,遞歸的方向很重要,一定要向已知的方向遞歸。對于上例而言,因為1的階乘是已知的,因此遞歸一定要追溯到1的階乘,遞歸一定要給定中止條件,這一點與循環類型。沒有中止條件的循環是死循環,不向中止點追溯的遞歸是無窮遞歸。



          注意:遞歸一定要向已知點追溯,這樣才能保證遞歸有結束的時候

           好程序員web前端培訓分享JavaScript學習筆記之遞歸函數,什么是遞歸函數在編程世界里面,遞歸就是一個自己調用自己的手段,遞歸函數: 一個函數內部,調用了自己,循環往復


          // 下面這個代碼就是一個最簡單的遞歸函數// 在函數內部調用了自己,函數一執行,就調用自己一次,在調用再執行,循環往復,沒有止盡function fn() {

          fn()}fn()

          · 其實遞歸函數和循環很類似

          · 需要有初始化,自增,執行代碼,條件判斷的,不然就是一個沒有盡頭的遞歸函數,我們叫做 死遞歸

          簡單實現一個遞歸

          · 我們先在用遞歸函數簡單實現一個效果

          · 需求: 求 1 至 5 的和

          · 先算 1 + 2 得 3

          · 再算 3 + 3 得 6

          · 再算 6 + 4 得 10

          · 再算 10 + 5 得 15

          · 結束

          · 開始書寫,寫遞歸函數先要寫結束條件(為了避免出現 “死遞歸”)

          function add(n) {

          // 傳遞進來的是 1 // 當 n===5 的時候要結束 if (n === 5) {

          return 5

          }}

          add(1)

          · 再寫不滿足條件的時候我們的遞歸處理

          function add(n) {

          // 傳遞進來的是 1 // 當 n===5 的時候要結束 if (n === 5) {

          return 5

          } else {

          // 不滿足條件的時候,就是當前數字 + 比自己大 1 的數字 return n + add(n + 1)

          }}add(1)

          預習:提前了解一下對象

          · 對象是一個復雜數據類型

          · 其實說是復雜,但是沒有很復雜,只不過是存儲了一些基本數據類型的一個集合

          var obj = {

          num: 100,

          str: 'hello world',

          boo: true}

          · 這里的 {} 和函數中的 {} 不一樣

          · 函數里面的是寫代碼的,而對象里面是寫一些數據的

          · 對象就是一個鍵值對的集合

          · {} 里面的每一個鍵都是一個成員

          · 也就是說,我們可以把一些數據放在一個對象里面,那么他們就互不干擾了

          · 其實就是我們準備一個房子,把我們想要的數據放進去,然后把房子的地址給到變量名,當我們需要某一個數據的時候,就可以根據變量名里面存儲的地址找到對應的房子,然后去房子里面找到對應的數據

          創建一個對象

          · 字面量的方式創建一個對象

          // 創建一個空對象var obj = {}

          // 像對象中添加成員obj.name = 'Jack'obj.age = 18

          · 內置構造函數的方式創建對象

          // 創建一個空對象var obj = new Object()

          // 向對象中添加成員obj.name = 'Rose'obj.age = 20

          · Object 是 js 內置給我們的構造函數,用于創建一個對象使用的

          在前面:本文為DataHunter前端技術培訓系列的第一篇文章,后續將有更多精彩內容放出,趕緊關注我們的公眾號來get實時更新吧!

          循環引用陷阱

          JavaScript的GC機制是自動進行。當一個對象斷開所有的指針引用以后,GC就會回收這部分資源。但循環引用會導致指針無法斷開,請看如下代碼:

          由于a和b兩個對象互相引用指針,形成了閉環,就會導致無法觸發GC,所占資源也就無法釋放。

          在JSON.stringify對JavaScript數據結構進行序列化的時候,也會遇到循環引用的陷阱。例如:

          JavaScript的數據類型和JSON序列化策略

          通過JavaScript的typeof操作符,我們可以得到的數據類型有

          string/number/ function/boolean/symbol/object/undefined。

          其中object包括Object/Array/RegExp/Date/null等,function包括class類。所有這些類型,從JSON序列化的角度,我們可以分為三類:

          由于JSON標準只具備string/number/boolean/null等有限的幾種值類型,所以JS對象在序列化后會有變化。下面是幾種特殊類型在轉換時需要注意的問題:

          • function無法被序列化。

          • Symbol對象無法被序列化。

          • Date對象無法被序列化。

          • ES6的class的typeof是function,無法序列化。

          • number的NaN會被轉成null。

          • RegExp默認會被轉成空對象。

          • TypedArray并不繼承自Array,所以會被序列化成對象而不是數組。

          • undefined由于會被JSON忽略,所以反序列化后對象會有鍵的變化。看例子:

          可以看到,in操作符在obj和copy兩個對象中會出現不同的返回結果。所以在對反序列化的數據進行操作時,in操作符要小心使用。

          通過JSON的序列化策略我們可以看出,循環引用可能會發生在mixed類型上,所以我們可以在序列化過程的最外層,建立一個mixed指針的數組。當數組已經具備此指針,就可以斷定該指針數據已經被序列化,從而中斷進一步序列化過程。

          首先我們寫一個mixed類型判斷函數:

          通過JSON.stringify的第二個回調處理理函數參數,我們植入這個類型判斷,并啟用循環引用陷阱規避。

          JavaScript對象的分支遞歸和深拷貝

          我們知道,Object.assign會實現一次Object或者Array的淺拷貝。但這種淺拷貝有時并不能滿足我們的需求。有時我們還會需要對對象的分支做值更改檢測,或者分支合并。這時候都需要對對象的所有分支做一次遞歸。

          JSON.stringify其實就是做了了一次分支遞歸。對象分支遞歸的策略和序列化策略基本一致,我們拿對象的深拷貝來舉例說明。

          我們首先針對上述三種數據類型,做一個類型判斷函數。

          此外,由于Object和Array都是mixed類型,但不是同一個構造函數,所以我們需要對Object和Array再做一次類型細分,以便構造新的復制對象。

          創建一個分支遞函數,并規避循環引用陷阱。

          可以看到循環引用的部分都變成undefined了。

          在ES6下,可以通過Symbol對象定義一個循環引用的標記并返回,在運行時對此類值做自定義的處理,防止對象log出來太難看。


          主站蜘蛛池模板: 免费无码一区二区三区| 风间由美性色一区二区三区| 精品无码国产AV一区二区三区| 亚洲福利一区二区| 射精专区一区二区朝鲜| 国产日本亚洲一区二区三区| 日本一区二区视频| 色噜噜一区二区三区| 久久精品道一区二区三区| 中文字幕亚洲综合精品一区| 国模极品一区二区三区| 国产一区二区三精品久久久无广告| 无码精品人妻一区二区三区中| 亚洲制服丝袜一区二区三区 | 日本片免费观看一区二区| 国产一区二区三区小向美奈子| 中文字幕无线码一区| 国模极品一区二区三区| 久久精品国产AV一区二区三区| 精品人体无码一区二区三区| 伊人久久精品无码麻豆一区| 波多野结衣在线观看一区| 99久久人妻精品免费一区 | 成人免费视频一区| 国产嫖妓一区二区三区无码| 精品国产日韩亚洲一区| 国产亚洲无线码一区二区| 无码av免费一区二区三区| 日本成人一区二区三区| 亚洲精品精华液一区二区 | 国产精品男男视频一区二区三区| 海角国精产品一区一区三区糖心 | 国产一区精品视频| 国产在线无码视频一区| 无码人妻久久一区二区三区| 精品视频在线观看一区二区| 亚洲一区二区三区免费观看| 亚洲国产一区视频| 一区二区视频在线观看| 国产精品资源一区二区| 大帝AV在线一区二区三区|