久久福利_99r_国产日韩在线视频_直接看av的网站_中文欧美日韩_久久一

您的位置:首頁技術(shù)文章
文章詳情頁

JavaScript數(shù)據(jù)類型對函數(shù)式編程的影響示例解析

瀏覽:252日期:2022-06-01 14:41:08
目錄
  • 前言
  • JavaScript中 的數(shù)據(jù)類型中的可變數(shù)據(jù)
    • 原始類型(基本類型)
    • 對象類型(引用類型)
  • JavaScript 為何能會讓純函數(shù)變得不純?
    • 如何解決可變數(shù)據(jù)的影響?
      • 數(shù)據(jù)拷貝
      • 使用不可變數(shù)據(jù)方案
    • 總結(jié)

      前言

      本篇文章是JavaScript 函數(shù)式編程 學(xué)習(xí)系列第二篇,感興趣也可以先去看第一篇:

      • 一文理解JavaScript中的函數(shù)式編程的概念
      • JavaScript數(shù)據(jù)類型對函數(shù)式編程的影響
      • 不可變數(shù)據(jù)方案之immer.js實(shí)現(xiàn)探索

      前文 一文理解JavaScript中的函數(shù)式編程的概念 中寫了函數(shù)式編程的概念,本篇文章繼上文之后,來梳理 JavaScript 數(shù)據(jù)類型對函數(shù)式編程的影響。

      函數(shù)式編程編程的核心就是 純函數(shù) 和隔離 副作用 ,為了讓 純函數(shù) 保持純粹,純函數(shù)的參數(shù)或者內(nèi)部引用的外部數(shù)據(jù)應(yīng)該是不可變數(shù)據(jù)。但 JavaScript 中的數(shù)據(jù)類型并不是都是不可變的,而數(shù)據(jù)類型的可變性,很有可能讓 純函數(shù) 變的不純。

      因此,本篇文章的目的有兩點(diǎn):

      • 探索 JavaScript 的數(shù)據(jù)類型來了解的可變數(shù)據(jù)的根源。
      • JavaScript 的可變數(shù)據(jù)數(shù)據(jù)是怎么讓 純函數(shù) 變得不純的?
      • 如何解決 可變數(shù)據(jù) 的影響?

      JavaScript中 的數(shù)據(jù)類型中的可變數(shù)據(jù)

      在 JavaScript 中,數(shù)據(jù)類型有以下 8 種:

      • null
      • undefined
      • boolean
      • number
      • symbol -- 在 es6 中被加入
      • bigint -- es6+ 被加入
      • object

      注意點(diǎn):

      在 JavaScript 中,變量是沒有類型的,值才有類型。變量可以在任何時(shí)候,持有任何值。

      原始類型(基本類型)

      上面 8 中類型除了 object ,其他都是原始類型,原始類型存儲的都是值,其特點(diǎn)有兩點(diǎn):

      • 沒有方法可以直接調(diào)用
      • 原始類型的數(shù)據(jù)是不可被改變的,改變一個(gè)變量的值,并不是把值改變了,而是讓變量擁有新的值。

      注意點(diǎn):

      • '1'.toString()或者false.toString()等可以用的原因是被強(qiáng)制轉(zhuǎn)換成了 String 類型也就是對象類型,所以可以調(diào)用 toString 函數(shù)。
      • 對于null來說,很多人會認(rèn)為它是個(gè)對象類型,其實(shí)是錯(cuò)誤的。typeof null 會輸出 object,這只是 JS 存在的一個(gè)悠久 Bug,而且好像永遠(yuǎn)不會也不會被修復(fù),因?yàn)橛刑嘁呀?jīng)存在的 web 的內(nèi)容依存著這個(gè) bug。注: 在 JS 的最初版本中使用的是 32 位系統(tǒng),為了性能考慮使用低位存儲變量的類型信息,000開頭代表是對象,然而 null 表示為全零,所以將它錯(cuò)誤的判斷為 object 。雖然現(xiàn)在的內(nèi)部類型判斷代碼已經(jīng)改變了,但是對于這個(gè) Bug 卻是一直流傳下來。

      對象類型(引用類型)

      而除了原始類型,剩下的 object 就是對象類型,和原始類型的不同點(diǎn)在于:原始類型存儲的是值,對象類型存儲的是地址。

      經(jīng)典示例:

      var c = 1;
      var d = c;
      d = 2;
      console.log(c === d) // false
      var a = {
          name: "張三",
          age: 20
      }
      var b = a;
      b.age = 21;
      console.log(a.age === b.age) // true
      

      示例中把變量 a 的值給到了變量 b , b 修改了age 屬性,但是 a 的 age 屬性也跟著變了,是因?yàn)?var b = a 是 a 把對象的引用地址賦值給 b ,這時(shí)候 a 和 b 指向的是內(nèi)存中的同一個(gè)數(shù)據(jù)。

      而 c 給 d 的是值,并不是一個(gè)引用,相當(dāng)于復(fù)制了一份數(shù)據(jù)。

      因此可以知道原型類型的數(shù)據(jù)是不可變的,而對象類型的數(shù)據(jù)是可變的。

      JavaScript 為何能會讓純函數(shù)變得不純?

      JavaScript 中的對象類型的數(shù)據(jù)是可變,而可變性,就代表了不確定性,純函數(shù) 中使用了不確性的數(shù)據(jù)就會導(dǎo)致不純,因?yàn)槠溥`背了 純函數(shù) 的特征:不受外界影響,不影響外界。

      下面來看一個(gè)例子:

      A 同學(xué)寫了這么一段代碼,初始化生成了一個(gè) “zhangsan” 用戶。

      export const defaultUserInfo = {
          name: "名稱",
          age: 20,
          hobby: ["玩耍"]
      };
      export function initUser(userTemplate, name, age) {
          const newUser = userTemplate;
          newUser.name = name;
          newUser.age = age;
          return newUser;
      }
      const zhangsan = userInit(userDefaultInfo, "zhangsan", 21);
      

      然后 B 同學(xué)在開發(fā)其他頁面的時(shí)候,看到有初始化用戶信息的方法,然后直接復(fù)制過去,初始化了一個(gè) “lisi” 用戶。

      import { defaultUserInfo, initUser } from "xxx模塊"。
      const lisi = userInit(userDefaultInfo, "lisi", 21);
      

      檢測的時(shí)候看到自己初始化的用戶信息正確的就沒有去檢查之前 A 同學(xué)的是否是正確的,上線后發(fā)現(xiàn)所有的用戶都變成了 lisi 。因?yàn)?userDefaultInfo 是一個(gè)引用類型,userInit(userDefaultInfo, "xxx", xx) 操作的都是內(nèi)存中的同一個(gè)對象。其原因就是因?yàn)?A 和 B 開發(fā)者犯了一個(gè)錯(cuò)誤,把可變數(shù)據(jù)傳遞到了 userInit 函數(shù)內(nèi)部進(jìn)行處理,哪怕進(jìn)行了淺層拷貝,也出現(xiàn)了問題。究其原因還是因?yàn)榻o函數(shù)傳遞進(jìn)去了一個(gè) 可變數(shù)據(jù)。

      我們校驗(yàn)一個(gè) 純函數(shù) 有效性的關(guān)鍵依據(jù),永遠(yuǎn)是“針對已知的輸入,能否給出符合預(yù)期的輸出”,而上面例子中 initUser 函數(shù)沒有違背這個(gè)規(guī)則,但是在可變數(shù)據(jù)的影響下,讓它產(chǎn)生了 副作用,對外界已有的數(shù)據(jù)造成了影響。

      如何解決可變數(shù)據(jù)的影響?

      數(shù)據(jù)拷貝

      從使用函數(shù)方的角度來看,既然造成這個(gè)問題的原因是因?yàn)閭鬟f進(jìn)去的數(shù)據(jù)是 可變數(shù)據(jù) ,那么我就復(fù)制一份數(shù)據(jù)傳遞給函數(shù)內(nèi)部使用,隨便你怎么修改,都不會影響外界其他數(shù)據(jù)。

      比如我們使用前面例子中的 initUser 函數(shù)時(shí),先拷貝一份數(shù)據(jù):

      function copyFunc(object) {
          return JSON.parse(JSON.string(object));
      }
      const zhangsan = userInit(copyFunc(userDefaultInfo), "zhangsan", 21);
      const lisi = userInit(copyFunc(userDefaultInfo), "lisi", 21);
      console.log(zhangsan.name === lisi.name); // false
      

      進(jìn)行拷貝后的數(shù)據(jù)傳遞給 userInit 函數(shù),就不會出現(xiàn)問題了。這里的 copyFunc 只能針對部分?jǐn)?shù)據(jù)類型,對不少類型是不支持的,具體可以去看一下 關(guān)于JSON.parse(JSON.stringify(obj))實(shí)現(xiàn)深拷貝應(yīng)該注意的坑 這篇文章。

      從被調(diào)用函數(shù)方來看,在使用 object 類型數(shù)據(jù)時(shí),函數(shù)內(nèi)部盡量不要去修改外界 object 數(shù)據(jù)(通過參數(shù)傳遞,或者直接使用外界的對象都不建議去修改),修改之前可以拷貝一份再修改。

      比如:

      export function initUser(userTemplate, name, age) {
          const newUser = copyFunc(userTemplate);
          newUser.name = name;
          newUser.age = age;
          return newUser;
      }
      

      使用不可變數(shù)據(jù)方案

      拷貝的數(shù)據(jù)比較大的時(shí)候,會出現(xiàn)性能問題,因此出現(xiàn)了不可變數(shù)據(jù)的方案。

      現(xiàn)在不可變數(shù)據(jù)常見的有兩種: Immutable.js 和 immer.js 。它們都能實(shí)現(xiàn)在操作數(shù)據(jù)后,返回新的一個(gè)數(shù)據(jù),而不影響之前的數(shù)據(jù)。

      Immutable.js 實(shí)現(xiàn)了持久化數(shù)據(jù)結(jié)構(gòu),實(shí)現(xiàn)原理說明(引用于immutable.js 和 immer):

      • 使用舊數(shù)據(jù)創(chuàng)建新數(shù)據(jù)時(shí),要保證舊數(shù)據(jù)同時(shí)可用且不變。同時(shí)為了避免 deepCopy 把所有節(jié)點(diǎn)都復(fù)制一遍帶來的性能問題,immutable 使用了結(jié)構(gòu)共享方式,即如果對象樹中的一個(gè)節(jié)點(diǎn)改變,只修改這個(gè)節(jié)點(diǎn)和受它影響的父節(jié)點(diǎn),其他節(jié)點(diǎn)共享。
      • immutable-js 使用了另一套數(shù)據(jù)結(jié)構(gòu) api,它會將原生數(shù)據(jù)類型都轉(zhuǎn)化為 immutable-js 內(nèi)部對象。

      因此 Immutable.js 需要嚴(yán)格使用它自定義的操作數(shù)據(jù)的方法才行。

      immer.js 利用了 es6 的 Proxy 來進(jìn)行對數(shù)據(jù)操作的攔截實(shí)現(xiàn),具體原理可去 剖析 Immer.js 工作原理與設(shè)計(jì)模式 這里看看,也可以去網(wǎng)上查詢。

      總結(jié)

      • 分析 JavaScript中 的數(shù)據(jù)類型中的可變數(shù)據(jù)根源:Object 數(shù)據(jù)結(jié)構(gòu)。
      • 探索了其可變數(shù)據(jù)數(shù)據(jù)是怎么對 純函數(shù) 造成的影響:Object 數(shù)據(jù)的不確定性。
      • 分析了如何解決 可變數(shù)據(jù) 的影響:深拷貝 和使用 不可變數(shù)據(jù)結(jié)構(gòu).

      參考:

      • JavaScript 函數(shù)式編程實(shí)踐指南
      • immutable.js 和 immer)

      以上就是JavaScript數(shù)據(jù)類型對函數(shù)式編程的影響示例解析的詳細(xì)內(nèi)容,更多關(guān)于JavaScript數(shù)據(jù)類型函數(shù)式編程的資料請關(guān)注其它相關(guān)文章!

      標(biāo)簽: JavaScript
      主站蜘蛛池模板: 亚洲日韩中文字幕一区 | 日韩一区中文字幕 | 欧美二区视频 | 一二三区在线 | 久久久毛片 | 国产剧情一区二区 | 奇米色777欧美一区二区 | 爱爱视频网站 | 激情久久av一区av二区av三区 | 免费av在线播放 | 国产在线小视频 | 亚洲精品电影网在线观看 | 亚洲一区欧美一区 | 欧美日韩国产精品久久久久 | 永久黄网站色视频免费 | 国产精品国产成人国产三级 | 夫妻午夜影院 | baoyu123成人免费看视频 | 成人二区| 高清av在线 | 亚洲综合大片69999 | 久久久一区二区三区 | 太平公主一级艳史播放高清 | 午夜影院在线观看 | 亚洲精品99| 成人久久18免费观看 | 亚州成人| 国产精品福利在线 | 婷婷色国产偷v国产偷v小说 | www.久久精品视频 | 亚洲无吗天堂 | 久久久久久国产精品 | 国产日韩欧美一区 | 免费大片在线观看网站 | 麻豆产精国品免费 | 久久久久国产精品一区二区三区 | 国产日韩欧美在线观看 | 在线中文字幕视频 | 91精品欧美久久久久久久 | 国产精品视频一区二区三区四蜜臂 | 国产人妖视频 |