二进制数据Knockout in Action

改章节是一篇关于二进制数据的帖子

    距离上一次写的文章已从前三个月了,由于我这个人总体来讲有懒散基因,项目一忙常常就不想干其他事了。还在项目总算已在收尾阶段了,在接下里的一段时间内我会陆续补上该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   )
这里的处理逻辑应该很简单了,就是非常直白地在“0”和“1”以及“false”和“true”之间做转化。

    然后我们再来切分从服务器来的数据,先写两个帮助函数:

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
从上面代码我们不难看出,首先通过ComputeOneZeroByOffset把原始数据通过二进制方式来获取对应的值,然后再通过 ComputeZeroOneToBool转化为界面上checkbox可以用来绑定的值。

    完整的运行结果如下,也可以通过JsFiddle直接查看源代码

    

 

    用一样的方法,我们可以做很多的扩展,假设界面上当初不是使用checkbox,而是使用多选的combobox,又该如何来实现呢?先让大家想想吧,可能后面的某一篇博客我会再来写一写我的实现方式。

 

文章结束给大家分享下程序员的一些笑话语录: IBM和波音777
  波音777是有史以来第一架完全在电脑虚拟现实中设计制造的飞机,所用的设备完全由IBM公司所提供。试飞前,波音公司的总裁非常热情的邀请IBM的技术主管去参加试飞,可那位主管却说道:“啊,非常荣幸,可惜那天是我妻子的生日,So..”..
  波音公司的总载一听就生气了:“胆小鬼,我还没告诉你试飞的日期呢!”


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值