1. 程式人生 > >比immutable 更簡潔的 immutability-helper 不可變資料操作之使用總結

比immutable 更簡潔的 immutability-helper 不可變資料操作之使用總結

immutability-helper因React官方出鏡,而被納入後宮,首席填坑官∙蘇南的專欄,梅斌的專欄

作者:首席填坑官∙蘇南
群:912594095,公眾號:honeyBadger8,本文原創,著作權歸作者所有,轉載請註明原連結及出處。

引言

  之前專案中遇到資料拷貝、引用之間資料層級巢狀過深,拷貝的值相互之間影響的問題,後來引入了immutability-helper,使用過程中的一些總結,跟大家分享下,至於為什麼不是immutable,請看下文分解,這裡是@IT·平頭哥聯盟,我是首席填坑官——蘇南

​  相信大家在面試/工作中都遇到過js物件/陣列的拷貝問題,面試官問你,你一般怎麼做??在現在ES6盛行的當下,不會一點ES6都不好意思說自己是前端(其實我一般都說自己是攻城獅、切圖崽

),我們想的大多第一想法,如下:

  • Object.assign - 最方便;
  • [...] - 最有逼格;
  • JSON.parseJSON.stringify - 完美組合;
  • $.extend() - jQuery時代的引領潮流時尚前沿的API;
  • 最後想到的才是自己遞迴實現一個;

  但是通常我們使用的Object.assign屬於淺拷貝,當資料巢狀層級較深時,就……呵呵了;而JSON.parse、stringify它應該是建立一個臨時可能很大的字串,然後又訪問解析器,效能是比較慢的。於是後來發現了 immutable「不可變資料」,曾經我也一度特別喜歡它,但時間久了,慢慢發現,它過於有個性了些、凡事都都沒有任何商量的餘地,所有的資料,從建立、變更、插入、刪除等操作,都要按它的套路來,對於我這種一生放蕩不羈愛自由的人來說,長時間的約束,是不能忍的;都說兩人如果三觀不合,是無法長久下去的,可能也是緣份吧,在後來的某一天偶然的閒逛中邂逅了新歡 ————

Immutability Helpers

  嗯,今天的主題就是給大家分享一下,Immutability Helpers的一些用法,會介紹API的使用操作和小技巧,如有不理解不對,請糾正:
  

太興奮了,差點忘了,補充一下,一個簡單的拷貝:

  //實現一個簡單的遞迴資料拷貝
  let customClone = (rawObj)=>{
    let copyObj = {};

    for (var key in rawObj) {
      if( typeof rawObj[key] === 'object' && Object.prototype.toString.call(rawObj[key]) !== '[object Array]'){
          copyObj[key] = customClone(rawObj[key]);
      }else{
          copyObj[key] = rawObj[key];,//首席填坑官∙蘇南的專欄,交流:912594095、公眾號:honeyBadger8
      };
    };
    return copyObj;
  };
  let objA =  {"name":"蘇南","sex":"男","height":"176"};
  let objB =  customClone(objA);
      objB.signature = "寶劍鋒從磨礪出,梅花香自苦寒來,做有溫度的攻城獅";

  console.log(objA);
  console.log(objB);

展示Object.assign拷貝問題

  • 補充一個 Object.assign 的坑 :
  let data = {
    a:1,
    b:2,
    children:{
      name:"蘇南",
      organization:"@IT·平頭哥聯盟",
      job:"首席填坑官",
      address:"ShenZhen",
      age:18
    }
  };
  let data2 = Object.assign({},data);
  data2.children.age = 28;
  data2.children.job = "首席甩鍋官";
  data2.b = 666;
  console.log("我是原始資料 data:",data);
  console.log("我是複製後的資料 data2:",data2);

展示Object.assign拷貝問題,公眾號:honeyBadger8

immutable 最後的一次回顧

  都說有了新歡,忘了舊愛,但我不是那種無情無義的人,最後正式介紹一下 immutable,為我倆的……畫上一個圓滿的句號:

  再次強調,並不是覺得immutable不好,不夠強大,只是自己個人觀點,有些不喜歡而已,各位immutable粉勿噴,想了解更多的同學可以點選這裡

Immutable data encourages pure functions (data-in, data-out) and lends itself to much simpler application development and enabling techniques from functional programming such as lazy evaluation.

使用示例:

  const list1 = List([ 1, 2, 3 ]);
  const list2 = List([ 4, 5, 6 ]);
  const array = [ 7, 8, 9 ];
  const list3 = list1.concat(list2, array);
  console.log(list3) // List {size: 9, _origin: 0, _capacity: 9, _level: 5, _root: null, …} 是不能直接獲取到資料的,須使用get,-- list3.get(0)

  let data = fromJS({
    obj:{}
  });
  let data1 = {
    a:1,
    b:2,
    children:{
      name:"蘇南",
    }
  };
  let data2 = data.mergeIn(['obj'],data1,{c:666});
  console.log("獲取的資料:",data2.getIn(['obj','c']));
  console.log("這裡是由formJS建立的資料:",data2.getIn(['obj','children','name']));//

immtublejs使用示例,簡單演示

使用immutable後,所有資料都要類似選擇器,一個一個往下選擇,並不是說它不好、功能不夠強大,只是自己有些不喜歡它類似JQuery選擇器一樣的語法,get、getIn、set、List等的使用方式,當然它也是可以使用 toJS方法轉回來的。

Immutability Helpers出場

gitHub上它對自己的介紹很簡單:Mutate a copy of data without changing the original source —— 在不更改原始源的情況下改變資料副本。

  與它結緣,是因為它在react官方文件中出鏡,而被我所寵幸,真的 ,只是因為在人群中多看了它一眼再也沒能忘掉, 它跟immutable不一樣,不會有那麼多條條框框約束你,給你自由、給你獨立的空間、給你獨立的思想,讓你想用即用、用之即走~~(泥馬,怎麼有點像張小龍說它的小程式一樣),但您放心,它的坑真的比小程式少,API也很簡潔,接下來來看一下,它的基本用法:

  • $push —— 陣列;
  • $unshift —— 陣列;
  • $splice —— 陣列;
  • $set —— 替換/覆蓋/合併原資料;
  • $toggle —— array of strings ,toggles a list of boolean fields from the target object;
  • $unset —— remove the list of keys in array from the target object;
  • $merge —— 合併物件;
  • $apply —— passes in the current value to the function and updates it with the new returned value;
  • $add —— 新增;
  • $remove —— 刪除。

以上基本就是它全部的API了,下面一起來看看,具體用法吧:

$push 的使用 :

  • 看名字就知道它的作用了啦,跟原生的push一樣,不過寫法有一點點不一樣;
  let arr = [1,2,3,4,5,66];
  let arr2 = update(arr,{
    $push : ["a","b","c"], //一定要 []號的形式哦,不可以 "a";
    [4]:{ // !!index ,可以指定修改下標的值
      $set:"我是首席填坑官"
    }
  });
  console.log(arr2);

$unshift 的使用 :

  • 一樣,跟原生的unshift,在原陣列開頭處插入,同樣寫法是以一個數組的形式;
  let arr = [1,2,3,4,5,66];
  let arr2 = update(arr,{
    $unshift : ["a","b","c"],//首席填坑官∙蘇南的專欄,交流:912594095、公眾號:honeyBadger8
    [4]:{
      $set:"我是首席填坑官∙蘇南"  //這裡需要注意,它的操作是在 unshift之前執行的,也就是在原 arr 上查詢 第4個下標
    }
  });
  console.log("原始陣列",arr);// [1, 2, 3, 4, 5, 66] 相互之間並不會影響
  console.log(arr2); //["a", "b", "c", 1, 2, 3, 4, "我是首席填坑官∙蘇南", 66]

$splice 的使用 :

  • 注意 :陣列套陣列,start,end, 插入的資料……,;

  let arr = [1,2,3,4,5,66];
  let arr2 = update(arr,{
    $splice : [[1,2,[66788,99],{a:123,b:"蘇南"}]], // or [0,1,"從我開始是插入的內容",88,89,90,"後面可以很多,是陣列、物件、字串都行"]
  });
  console.log(arr2); 

  //複雜一些的用法:
  let obj={
    name:"immutable",
    list :[1,2,[90,55,44,3,22,55],3,4,6,7,8]
  };
  let obj2 = update(obj,{
    list:{
      [2]:value=>update(value,{
        $splice:[[0,2]]  // [90,55,44,3,22,55] => [44, 3, 22, 55]
      })
    }
  });

immutability-helper $splice的使用展示

 $splice的使用展示,格式錯誤的警告

$set 的使用 :

  • 上面已經演示過了,其實有點替換的意思,當有重複的值時,就會覆蓋,沒有就新增,來展示覆雜一點的場景,層級深的資料,也不會相互影響;
  let obj={
    name:"immutable",
    children:{
      address:"ShenZhen",
      hobby:"@IT·平頭哥聯盟-前端開發"
    }
  };
  let obj2 = update(obj,{
    $set : {name:"immutability-helper",other:"其他欄位,如微信公眾號:honeyBadger8,每週為你帶來最新分享"}
  });
  let obj3 = update(obj,{
    name:{
      $set : "蘇南"
    },
    children:{
      hobby:{
        $set:"首席填坑官 - javascript"
      }
    }
  });
  console.log("原始資料:",obj); 
  console.log("obj2:",obj2); 
  console.log("obj3",obj3); 

immutability-helper $set的使用展示

$toggle 的使用:

  • 聽名字,應該就能猜出來,開關切換的意思;
  • Boolean 布林值的切換,如果你是強制要 Number 型別 的 0、1,那麼使用引方法的時候就要注意了;
  let obj={
    name:"immutable",
    a:false,
    b:true,
    c:1,
    d:0
  };
  let obj2 = update(obj,{
    $toggle:['b','a',"c","d"],
  });
  console.log("原始資料:",obj);
  console.log("obj2:",obj2);

immutability-helper $toggle的使用展示

$unset 的使用:

  • 它跟$set相反,有點remove的味道,但又貌似有不同的之處,當操作的物件為object時key是刪除了;而陣列array中它的值沒有了,卻保留了下標,不改變陣列的長度,刪除陣列建議還是用$splice;請看下圖:
  let arr = [1,2,3,4,5,6];
  let obj={
    name:"immutable",,//首席填坑官∙蘇南的專欄,交流:912594095、公眾號:honeyBadger8
    children:{
      address:"ShenZhen",
      hobby:"寫部落格"
    }
  };
  let obj2 = update(obj,{
    $unset : ["name"],
    children:{
      $unset:["address"]
    }
  });
  console.log("原始資料:",obj);
  console.log("obj2:",obj2);

  let arr2 = update(arr,{
    $unset : [1]
  });
  console.log("arr2:",arr2,arr2.length);

immutability-helper $unset的使用展示

$merge 的使用:

  • $merge 跟我們最愛的Object.assign一樣,做合併操作的,但它比assign優秀很多,深層次拷貝,不會相互影響 :
  let arr = [1,2,3,4,5,6];
  let obj={
    name:"immutable",
    children:{
      address:"ShenZhen",
      hobby:"寫部落格",
      array:["我不是程式設計師","切圖崽瞭解一下"],
    }
  };
  let obj2 = update(obj,{
    $merge:{
      arr
    },
    children:{
      array:{
        $merge:{items:["從前有坐山","山裡有個廟"]},
        $splice:[[3,0,"住著一個小和尚"]]
      }
    }
  });
  console.log("原始資料:",obj);
  console.log("obj2:",obj2);

$merge的使用展示,做有溫度的攻城獅

$apply 的使用:

  • $apply 基於當前值進行一個函式運算,從而得到新的值 :
  • 注意 :它必須是一個 function 哦!
  let obj={
    name:"immutable",
    children:{
      items:["從前有一坐山"],
      array: [1,2,3,4,5,6],
    }
  };
  let obj2 = update(obj,{
    name:{
      $apply:(val)=>("首席填坑官")
    },
    children:{
      items:{
        $apply:(val)=>{
          console.log("舊值",val);
          return [3,0,"住著一個小和尚"]
        }
      },
      array:{
        $apply:(val)=>(val.reverse()) //必須是一個函式
      }
    }
  });
  console.log("原始資料:",obj);
  console.log("obj2:",obj2);

$apply的使用展示

$apply的使用展示,必須是function的錯誤警告

$remove 的使用:

  • $remove 一定一定 要是使用SetMap 建立的陣列:
  • 要刪除的值,必須是陣列成存在的,如值不存在則忽略,$remove:[2,666],2會刪除,6則會被忽略;
  • 這個api有點奇怪,正常普通的陣列 [],這樣的刪除不了!!;
  • 常見錯誤如下圖:
  let obj={
    name:"immutable",
    children:{
      array:new Set([1, 2, 3, 4, 4]),
    }
  };
  let obj2 = update(obj,{
    children:{
      array:{
        $remove:[2],
      },
    }
  });
  console.log("原始資料:",obj);
  console.log("obj2:",obj2);

$remove的使用展示,必須是 new Set Map建立

必須是 new Set Map建立的報錯

$add 的使用:

  • $add 跟剛才的 $remove 一樣要使用Map/Set,$add方法也跟 es6 Map/Set的 add方法一致:
  • 只是寫的時候也要注意一些, [ [] ] ,巢狀!
  let obj={
    name:"immutable",
    array:new Map([["a",1],["b",2]]),
  };
  let obj2 = update(obj,{
    array:{
      $add:[["66",56]],
    },
  });
  console.log("原始資料:",obj);
  console.log("obj2:",obj2);
  console.log("獲取key a:",obj2.array.get('a'));

本文由@IT·平頭哥聯盟-首席填坑官∙蘇南 分享

Immutability Helpers的高階用法:

  • 還可以自定義方法,如 定義一個 $trinocular 方法,來判斷陣列中的值;
  • 只是一個簡單的示例,更多複雜的用法,可以自己去探索哦 去官方 github
    update.extend('$trinocular', function(proportion, original) {
    return  original > 88 ? (original/proportion ): (proportion+original);
    });
    let array =[56,33,55,777,322,444,61,12,34,52,245];
    let array2 = array.map((k,v)=>update(k,{
    $trinocular:2
    }))
    console.log("原始資料:",array);
    console.log("array2:",array2);

    immutability-helper 高階用法

總結/結尾:

  以上就是基礎 API 的用法 ,添加了一些官方示例沒有講到的組合使用,以及使用過程中,可能出現的一些錯誤,需要留意的地方,更多定製高階用法,有興趣的同學可以自行了解一下。

  以上就是今天為大家帶來的分享,它可能沒有 immutable 那麼多功能,但貴在簡潔,不會有太多的約束,如理解有誤之處,歡迎各位大佬糾正,畢竟我還只是個寶寶——新手上路中!。

  下方是我弄的一個公眾號,歡迎關注,以後文章會第一時間,在公眾號上更新,原因是之前分享的有兩篇文章,竟然被其他公眾號抄襲了,前些天去更新發表的時候,微信提示我文章已經不是原創了檢測到相同的文章,寶寶心裡那個涼啊~,果斷申訴告了對方(是一個培訓學校公眾號,好氣哦),補了簡書釋出的連結和截圖日期,萬幸最後勝訴了!

寶劍鋒從磨礪出,梅花香自苦寒來,做有溫度的攻城獅!

更多文章:

淺談easy-mock 最好的備胎沒有之一
如何給localStorage設定一個過期時間?
immutability因React官方出鏡之使用總結分享!
小程式專案之做完專案老闆給我加了6k薪資~
小程式專案之填坑小記
面試踩過的坑,都在這裡了~
你應該做的前端效能優化之總結大全!
動畫一點點 - 如何用CSS3畫出懂你的3D魔方?
動畫一點點 - 手把手教你如何繪製一輛會跑車
SVG Sprites Icon的使用技巧

作者:蘇南 - 首席填坑官
連結:https://blog.csdn.net/weixin_43254766/article/details/83472544
交流:912594095、公眾號:honeyBadger8
本文原創,著作權歸作者所有。商業轉載請聯絡@IT·平頭哥聯盟獲得授權,非商業轉載請註明原連結及出處。