改章节是一篇关于二进制数据的帖子
距离上一次写的文章已从前三个月了,由于我这个人总体来讲有懒散基因,项目一忙常常就不想干其他事了。还在项目总算已在收尾阶段了,在接下里的一段时间内我会陆续补上该web项目的一些心得体会或者碰到的问题。
在项目中我碰到了这样的一个需求(这里进行了简化),有一个配置页面须要告诉用户以后数据是从哪里来的,数据起源是固定的并且这些数据源可以同时被选中,这里为了简单起见假设是4个。然后从服务器传过来的数据是一个整数,须要从二进制角度来处理,即是4位二进制数,最低位表现是不是来自于数据源01,倒数第二位表现是不是来自于数据源02,以此类推。比如以后数据同时来自于4个数据源,则服务器就会传“15”这个数字过来(即二进制“1111”);如果以后数据只来自于数据源03,则该数就是“4”(即二进制“0100”)。
界面如下图所示:
我的任务就是能写通用的方法来处理这个情况,因为还有其他一些数据也须要用二进制方式处理。
让我们从上到下来斟酌这个问题,首先第一步从界面上可以看到我们须要操纵4个checkbox,而用于checkbox的绑定关键字是“checked”,须要传入布尔类型的值。由于从服务器来的数据须要从二进制角度来处理,天然这里就可以想到须要一个方法把数字“0”和“1”分别转化为布尔类型的“false”和“true”。然后第二步就是通过服务器的数据把每一个数据源的数据根据二进制切分出来。
先用一个computed observable方法来处理第一步的数据:
1 ComputeZeroOneToBool = (zeroOrOneObservable) -> 2 return undefined if not ko.isObservable(zeroOrOneObservable) 3 4 return ko.computed( 5 read: -> 6 zeroOrOne = ko.utils.unwrapObservable zeroOrOneObservable 7 return zeroOrOne is 1 8 write: (value) -> 9 if value 10 zeroOrOneObservable 1 11 else 12 zeroOrOneObservable 0 13 return 14 )
然后我们再来切分从服务器来的数据,先写两个帮助函数:
1 _getBitByOffset = (integerValue, offset) -> 2 return integerValue >> offset & 0x1 3 4 _setBitByOffset = (integerValue, offset, bitValue) -> 5 if bitValue is 1 6 return (1 << offset) | integerValue 7 else 8 return ~(1 << offset) & integerValue
假设服务器传过来一个数“12”,那么转化为二进制就是“1100”,那么如果我要取倒数第三位的值该如何做呢?我们可以把这个数先右移两位,从二进制来看就是把“1100”变为“0011”,从而把倒数第三位的值移到了最低位。然后最低位再和“1”这个数做“与”操纵,这样就能得到倒数第三位的值了。上面代码的第5行就做了这样的操纵。
另一方面,我又该如何改变某一位的值呢?先来看上面代码第8行,这句代码是用来把某一位设为“0”。比如还是“12”(即二进制“1100”),我要把倒数第三位的值设为“0”,从而使该数变为“8”(即二进制“1000”)。我们可以先把“0001”右移两位变为“0100”,然后取反变为“1011”,再和原值“1100”做“与”操纵就得到了“1000”。
再来看上面代码的第6行,这句代码是用来把某一位设为“1”。比如把上面例子反一下,把“1000”的倒数第三位的值设为“1”。我们可以先把“0001”右移两位变为“0100”,然后直接和原值“1000”做“或”操纵就得到了“1100”。
有这两个帮助函数后,就可以写从原始数据中获取指定位置二进制值的函数了:
1 ComputeOneZeroByOffset = (integerObservable, offset)-> 2 return ko.computed( 3 read: -> 4 integerValue = parseInt ko.utils.unwrapObservable integerObservable() 5 return _getBitByOffset integerValue, offset 6 write: (value) -> 7 integerValue = parseInt ko.utils.unwrapObservable integerObservable() 8 integerObservable _setBitByOffset integerValue, offset, value 9 return 10 )
接下来就是来看我们该如何使用上面的函数:
1 rawData = ko.observable 12 2 3 input01Value = ComputeOneZeroByOffset rawData, 0 4 input02Value = ComputeOneZeroByOffset rawData, 1 5 input03Value = ComputeOneZeroByOffset rawData, 2 6 input04Value = ComputeOneZeroByOffset rawData, 3 7 8 input01Checked = ComputeZeroOneToBool input01Value 9 input02Checked = ComputeZeroOneToBool input02Value 10 input03Checked = ComputeZeroOneToBool input03Value 11 input04Checked = ComputeZeroOneToBool input04Value
完整的运行结果如下,也可以通过JsFiddle直接查看源代码
用一样的方法,我们可以做很多的扩展,假设界面上当初不是使用checkbox,而是使用多选的combobox,又该如何来实现呢?先让大家想想吧,可能后面的某一篇博客我会再来写一写我的实现方式。
文章结束给大家分享下程序员的一些笑话语录: IBM和波音777
波音777是有史以来第一架完全在电脑虚拟现实中设计制造的飞机,所用的设备完全由IBM公司所提供。试飞前,波音公司的总裁非常热情的邀请IBM的技术主管去参加试飞,可那位主管却说道:“啊,非常荣幸,可惜那天是我妻子的生日,So..”..
波音公司的总载一听就生气了:“胆小鬼,我还没告诉你试飞的日期呢!”