作者:首席填坑官∙苏南
公Z好:honeyBadger8,群:912594095,本文原创,著作权归作者所有,转载请注明原链接及出处。

引言

  之前项目中遇到数据拷贝、引用之间数据层级嵌套过深,拷贝的值相互之间影响的问题,后来引入了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];};};return copyObj;};let objA =  {"name":"苏南","sex":"男","height":"176"};let objB =  customClone(objA);objB.signature = "宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮";console.log(objA);console.log(objB);复制代码
  • 补充一个 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);复制代码

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']));//复制代码

使用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"],[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]})}});复制代码

$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);
复制代码

$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);复制代码

$unset 的使用:

  • 它跟splice`;请看下图:
  let arr = [1,2,3,4,5,6];let obj={name:"immutable",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);复制代码

$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);复制代码

$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);复制代码

$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);
复制代码

$add 的使用:

  • $add 跟刚才的 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'));复制代码

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);
复制代码

总结 :以上就是基础 API 的用法 ,添加了一些官方示例,没有讲到的组合使用,以及使用过程中,可能出现的一些错误,需要留意的地方,更多定制高级用法,有兴趣的同学可以自行了解一下。

  以上就是今天为大家带来的分享,它可能没有 immutable 那么多功能,但贵在简洁,不会有太多的约束,如理解有误之处,欢迎各位大佬纠正,毕竟我还只是个宝宝——新手上路中!?。

  下方是我弄的一个公众号,欢迎关注,以后文章会第一时间,在公众号上更新,原因是之前分享的有两篇文章,竟然被其他公众号抄袭了?,前些天去更新发表的时候,微信提示我文章已经不是原创了检测到相同的文章,宝宝心里那个凉啊~,果断申诉告了对方(是一个培训学校公众号,好气哦),补了掘金发布的链接和截图日期,万幸最后胜诉了?!??

作者:苏南 - 首席填坑官
链接:honeybadger8.github.io/blog/
交流:912594095、公Z好:honeyBadger8
本文原创,著作权归作者所有。商业转载请联系@IT·平头哥联盟获得授权,非商业转载请注明原链接及出处。

immutability因React官方出镜之使用总结分享!相关推荐

  1. 地图统计_庄园地图“出镜率”排名,500场数据统计,红教堂第一

    在11赛季的时候很多玩家都私信趣游君,他们感觉自己排位经常会遇到一些让人讨厌的地图,也是因为经常遇到这些地图,所以导致自己的排位赛迟迟无法上分,因为要求我们做一下地图出镜率的排名. 为了完成这个刷剧统 ...

  2. 明星“真空”出镜上直播,这戏该如何继续演?

    世界著名作家.大思想家斯宾塞.约翰逊曾经说过"唯一不变的是变化本身",这句名言也是当前互联网时代下各行业的真实写照.风口是接二连三的变换,独角兽的面孔也是日新月异,就连原本高高在上 ...

  3. 自媒体原创视频怎么做?这3个领域无需出镜

    如果说2021年是短视频的天下,相信没有自媒体人会反驳我吧?随着短视频行业的盛势发展,越来越多的年轻人也想要投入这行,但又苦于不想出镜.今天就给大家介绍一下,那些无需出镜的短视频领域: 01 电影剪辑 ...

  4. React 官方纪录片:我们亲手将 JSX 推向神坛!

    前言 自从 Vue 纪录片发布后,国外粉丝就开始疯狂催更 React 纪录片,虽说在国内 Vue 是最流行的框架,但如果放眼全世界的话 React 才是一哥,所以它的粉丝量也比 Vue 的体量大了很多 ...

  5. 用TypeScript来写React官方入门教程 .tsx后缀文件,同时入门typescript和React

    用TypeScript来写React官方入门教程 .tsx后缀文件,同时入门typescript和React 1. 项目说明: 这是React官网上那个下井字棋的入门教程,但是我把它换了typesci ...

  6. 在TEASOFT中如何设置出镜摄像头?

    ➤01 背景 1.TEASOFT软件 在 TEASOFT教学软件 中,需要设置主摄像头所在窗口的Caption(标题)和相应的尺寸. TEASOFT软件的主摄像头主要是用于主讲者在屏幕中的出镜镜头.它 ...

  7. 企业网络推广中关键词“出镜率”高会影响企业网络推广吗?

    为了帮助企业网站在搜索引擎中获得最佳位置,站长通过网站优化助力网站运营,提升网站收录.网站关键词排名以及网站权重等,为企业网站在搜索引擎中获得更多加分优化行为.那么在网站关键词优化中关键词出现频率越高 ...

  8. 真人出镜,微信视频号第一期视频来了!

    微信最近悄悄上线了「视频号」功能,入口在朋友圈的下方,由此可以看出「视频号」此功能的权重. 有些朋友应该有入口了,可以看到一些视频,但不能发视频. 可能还有部分的人没有出现这个入口,别着急,现在还处于 ...

  9. [react] 写出React动态改变class切换组件样式

    [react] 写出React动态改变class切换组件样式 export default memo(function Demo(){const [clsName,setClsName] = useS ...

  10. [react] 说出几点你认为的React实践

    [react] 说出几点你认为的React最佳实践 使用HOC实现组件复用 完善测试用例Testing 使用Typescript或者Flow对代码进行静态检测 代码规范及格式化ES lint, Pre ...

最新文章

  1. eclipes 安装 pytdev,svn,插件
  2. 输入4个同学的姓名学号,语文数学英语信息计算平均成绩,按平均成绩高低排序输出java,c++实现
  3. 问题 A: 喷水装置(一)
  4. VC6.0 控件Radio Button的使用
  5. 用strtotime()和date()函数算出2019年9月的周日日期
  6. Halcon算子学习:surface_normals_object_model_3d
  7. html隐藏并失效,如果元素开始隐藏,css过渡将不起作用
  8. Docker(十二)关于deployment 创建的小坑
  9. Mysql中有哪些数据类型(建议收藏)
  10. 平安人寿打造新一代年金保险产品:御享财富和御享金瑞
  11. java 变量的命名
  12. 谷歌身份验证器 api_如何验证任何Google API
  13. IOS高德地图使用说明
  14. Tableau5——地图,仪表板
  15. easyPoi导出Excel,WPS可以打开,office却打不开的问题
  16. Deblur-NeRF CVPR 2022
  17. 网络管理——直接网络管理规范
  18. python中map函数返回值类型_Python学习第42课-map()函数
  19. java实现九九乘法表算法
  20. 大数据基础原理与应用

热门文章

  1. .net GridView绑定数据、编辑、更新、删除(弹出确认对话框)、取消、根据条件隐藏或显示按钮操作
  2. GIT每次上传代码都必须输入用户名解决方案
  3. c语言中运用空语句的延时函数,【转载】单片机C语言中_nop_函数的使用及C语言的延时计算...
  4. objdump: ‘1443.14.0)‘: No such file or directory
  5. 从openjdk.java.net获取OpenJDK8源码并编译(amd64/aarch64/arm64)
  6. eclipse ARM/AARCH64版本下载
  7. BAT判断一个目录是否存在
  8. com.jogamp.opengl.GLException: J3D-Renderer-1: createImpl ARB n/a but required, profile > GL2 reques
  9. JDK11竟然不支持字体斜体
  10. sudo rpm安装时$USER是root