av一区二区在线观看_亚洲男人的天堂网站_日韩亚洲视频_在线成人免费_欧美日韩精品免费观看视频_久草视

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

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

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

      前言

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

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

      前文 一文理解JavaScript中的函數(shù)式編程的概念 中寫了函數(shù)式編程的概念,本篇文章繼上文之后,來梳理 JavaScript 數(shù)據(jù)類型對(duì)函數(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 ,其他都是原始類型,原始類型存儲(chǔ)的都是值,其特點(diǎn)有兩點(diǎn):

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

      注意點(diǎn):

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

      對(duì)象類型(引用類型)

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

      經(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 把對(duì)象的引用地址賦值給 b ,這時(shí)候 a 和 b 指向的是內(nèi)存中的同一個(gè)數(shù)據(jù)。

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

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

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

      JavaScript 中的對(duì)象類型的數(shù)據(jù)是可變,而可變性,就代表了不確定性,純函數(shù) 中使用了不確性的數(shù)據(jù)就會(huì)導(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);
      

      檢測(cè)的時(shí)候看到自己初始化的用戶信息正確的就沒有去檢查之前 A 同學(xué)的是否是正確的,上線后發(fā)現(xiàn)所有的用戶都變成了 lisi 。因?yàn)?userDefaultInfo 是一個(gè)引用類型,userInit(userDefaultInfo, "xxx", xx) 操作的都是內(nèi)存中的同一個(gè)對(duì)象。其原因就是因?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)是“針對(duì)已知的輸入,能否給出符合預(yù)期的輸出”,而上面例子中 initUser 函數(shù)沒有違背這個(gè)規(guī)則,但是在可變數(shù)據(jù)的影響下,讓它產(chǎn)生了 副作用,對(duì)外界已有的數(shù)據(jù)造成了影響。

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

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

      從使用函數(shù)方的角度來看,既然造成這個(gè)問題的原因是因?yàn)閭鬟f進(jìn)去的數(shù)據(jù)是 可變數(shù)據(jù) ,那么我就復(fù)制一份數(shù)據(jù)傳遞給函數(shù)內(nèi)部使用,隨便你怎么修改,都不會(huì)影響外界其他數(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ù),就不會(huì)出現(xiàn)問題了。這里的 copyFunc 只能針對(duì)部分?jǐn)?shù)據(jù)類型,對(duì)不少類型是不支持的,具體可以去看一下 關(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ù)傳遞,或者直接使用外界的對(duì)象都不建議去修改),修改之前可以拷貝一份再修改。

      比如:

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

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

      拷貝的數(shù)據(jù)比較大的時(shí)候,會(huì)出現(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)共享方式,即如果對(duì)象樹中的一個(gè)節(jié)點(diǎn)改變,只修改這個(gè)節(jié)點(diǎn)和受它影響的父節(jié)點(diǎn),其他節(jié)點(diǎn)共享。
      • immutable-js 使用了另一套數(shù)據(jù)結(jié)構(gòu) api,它會(huì)將原生數(shù)據(jù)類型都轉(zhuǎn)化為 immutable-js 內(nèi)部對(duì)象。

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

      immer.js 利用了 es6 的 Proxy 來進(jìn)行對(duì)數(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ù)是怎么對(duì) 純函數(shù) 造成的影響:Object 數(shù)據(jù)的不確定性。
      • 分析了如何解決 可變數(shù)據(jù) 的影響:深拷貝 和使用 不可變數(shù)據(jù)結(jié)構(gòu).

      參考:

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

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

      標(biāo)簽: JavaScript
      主站蜘蛛池模板: 91精品91久久久中77777 | 中文字幕不卡在线 | 黄色精品网站 | 黄色中文字幕 | 国产小视频在线 | 伊人精品 | 黄色高潮视频 | 九九热精品 | 欧美一级免费看 | 亚洲综合免费 | 亚洲美女毛片 | 不卡中文字幕 | 免费av在线 | 蜜桃在线观看视频 | 国产乱码精品一区二区三 | 黄色www| 国产精品99999 | 亚洲欧美中文字幕 | 免费国产黄色 | 欧美性猛交xxxx黑人猛交 | 日本在线免费观看 | 香蕉视频一区 | 久久久婷婷 | 欧美 日韩 国产 成人 在线 | 国产精品羞羞答答 | 亚洲综合三区 | 亚洲欧美日韩国产精品 | 婷婷色在线| 在线国产小视频 | 国产综合一区二区 | 国产成人av网站 | 中文字幕免费观看视频 | 伊人av网| 一区二区三区影院 | 黄色一级视频网站 | 欧美精品一级片 | 黄色免费毛片 | 免费一级毛片 | 日韩免费观看 | av高清在线 | 91青青草 |