最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Vue3 源码中的位运算,又一个面试考点

    正文概述 掘金(FinGet)   2021-04-01   463

    Vue3中的位运算

    在vue3的源码中,实现了一个ShapeFlags(对元素进行标记判断是普通元素、函数组件、​插槽、 keep alive 组件等等)这里不展开讲。

    export const enum ShapeFlags {
      ELEMENT = 1,
      FUNCTIONAL_COMPONENT = 1 << 1,
      STATEFUL_COMPONENT = 1 << 2,
      TEXT_CHILDREN = 1 << 3,
      ARRAY_CHILDREN = 1 << 4,
      SLOTS_CHILDREN = 1 << 5,
      TELEPORT = 1 << 6,
      SUSPENSE = 1 << 7,
      COMPONENT_SHOULD_KEEP_ALIVE = 1 << 8,
      COMPONENT_KEPT_ALIVE = 1 << 9,
      COMPONENT = ShapeFlags.STATEFUL_COMPONENT | ShapeFlags.FUNCTIONAL_COMPONENT
    }
    
    
     if (shapeFlag & ShapeFlags.ELEMENT || shapeFlag & ShapeFlags.TELEPORT) {
      ...
    }
    
    
    if (hasDynamicKeys) {
          patchFlag |= PatchFlags.FULL_PROPS
        } else {
        if (hasClassBinding) {
          patchFlag |= PatchFlags.CLASS
        }
        if (hasStyleBinding) {
          patchFlag |= PatchFlags.STYLE
        }
        if (dynamicPropNames.length) {
          patchFlag |= PatchFlags.PROPS
        }
        if (hasHydrationEventBinding) {
          patchFlag |= PatchFlags.HYDRATE_EVENTS
        }
    }
    

    上面的代码都是vue3源码中的片段,其中有<<,&,|=这几个平时基本上不会用到运算法,本文就总结一下前端需要掌握的位运算。

    Tips

    原码,反码,补码

    • 原码: 最高位表示符号位,正数为0,复数为1(以基于四个bits操作为例)
    10 = 01010  // 原码 
    -10 = 11010  // 原码
    
    • 反码(one's complement): 在原码的基础上符号位不变,正数不变,负数取反,为了解决+1-1相加不等于0的问题
    10 = 01010 // 反码
    -10 = 10101 // 反码
    
    10 + (-10)= 01010 + 10101 = 11111 = -0
    
    • 补码 : 在反码的基础上,正数不变,负数再加1(逢二进一),解决了+0 -0,有两个零的问题。
    -10 = 10110 // 补码
    

    进制转换

    
    /**
     * 十进制转其他进制
     * @param  {[type]} num   [数字]
     * @param  {[type]} radix [进制]
     * @return {[type]}       [返回一个radix进制的数]
     */
    function convert(num,radix){
    	return parseInt(num).toString(radix);
    }
    convert(123,2);
    
    /**
     * 其他进制转10进制
     * @param  {[type]} num   [数字]
     * @param  {[type]} radix [进制]
     * @return {[type]}       [返回一个10进制数字]
     */
    function convert10(num, radix){
    	return parseInt(num, radix);
    }
    

    &(按位与),~(按位非),^(异或),|(或)

    &(按位与)

    const a = 5;        // 00101
    const b = 3;        // 00011
    
    console.log(a & b); // 00001
    // 1
    

    Vue3 源码中的位运算,又一个面试考点

    真值表: (都为1,值才为1)

    aba AND b
    000010100111
    const a = 5;        // 00101
    const b = -3;        // 10011(原),11100(反),11101(补)
    
    console.log(a & b); // 00101 
    // 5
    

    ~(按位非)

    把每一位都反转一下:

    const a = 5;     // 00101
    
    console.log(~a); // 11010 != -6
    //  -6
    

    就来看看~5的计算步骤:

    1. 将5转二进制 = 00000101
    2. 按位取反 = 11111010
    3. 发现符号位(即最高位)为1(表示负数),将除符号位之外的其他数字取反 = 10000101
    4. 末位加1取其补码 = 10000110
    5. 转换回十进制 = -6

    负数的运算,要先找出补码,然后再取反。

    ~-5的计算步骤:

    1. 将-5转二进制 = 10000101
    2. 按位取反得到反码 = 11111010
    3. 末位加1取其补码 = 11111011
    4. 再次取反 = 00000100
    5. 转换回十进制 = 4

    ~~ 和 parseInt :

    ~~ 5.2 = - ((-(5 + 1)) + 1) = - (-6 + 1) = 5 === parseInt(5.2)
    

    在 ECMAScript® Language Specification 中是这样描述位操作符的:

    The production A : A @ B, where @ is one of the bitwise operators in the productions above, is evaluated as follows:
    
    1. Let lref be the result of evaluating A.
    2. Let lval be GetValue(lref).
    3. Let rref be the result of evaluating B.
    4. Let rval be GetValue(rref).
    5. Let lnum be ToInt32(lval).
    6. Let rnum be ToInt32(rval).
    7. Return the result of applying the bitwise operator @ to lnum and rnum. The result is a signed 32 bit integer.
    

    需要注意的是第5和第6步,按照ES标准,两个需要运算的值会被先转为有符号的32位整型。所以超过32位的整数会被截断,而小数部分则会被直接舍弃。

    ^(异或)

    同一位置不相等,则为1。

    const a = 5;     // 00101
    const b = 3;     // 00011
    
    console.log(a ^ b); // 00110
    //  6
    

    Vue3 源码中的位运算,又一个面试考点

    真值表:

    aba XOR b
    000011101110

    leetcode: 只出现一次的数字

    给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
    
    说明:
    
    你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
    
    示例 1:
    
    输入: [2,2,1]
    输出: 1
    
    var singleNumber = function(nums) {
        for(let i = 1;i<nums.length;i++) {
            nums[0] = nums[0] ^ nums[i]
        }
        return nums[0]
    };
    

    |(或)

    同一位置有一个1则为1.

    const a = 5;     // 00101
    const b = 3;     // 00011
    
    console.log(a | b); // 00111
    //  7
    

    Vue3 源码中的位运算,又一个面试考点

    5 | -3负数的按位或:

    1. 5的原码 = 0000101
    2. -3的原码 = 1000011,反码 = 1111100, 补码 = 1111101
    3. 5 | -3 = 1111101
    4. 发现符号位(即最高位)为1(表示负数),将除符号位之外的其他数字取反 = 1000010
    5. 末位加1取其补码 = 1000011
    6. 转换回十进制 = -3

    真值表:

    aba OR b
    000011101111

    <<(左移),>>(右移), >>>(无符号右移),

    <<(左移)

    左移操作符 (<<) 将第一个操作数向左移动指定位数,左边超出的位数将会被清除,右边将会补零。

    const a = 5; // 00000101
    a << 2 // 00010100 = 20
    

    Vue3 源码中的位运算,又一个面试考点

    a << 4 = a * 24 = a * 16 = 80;

    >>(右移)

    该操作符会将第一个操作数向右移动指定的位数。向右被移出的位被丢弃,拷贝最左侧的位以填充左侧。由于新的最左侧的位总是和以前相同,符号位没有被改变。所以被称作“符号传播”。

    const a = 5; // 00000101
    a >> 2 // 00000001 = 1
    

    Vue3 源码中的位运算,又一个面试考点

    >>>(无符号右移)

    该操作符会将第一个操作数向右移动指定的位数。向右被移出的位被丢弃,左侧用 0 填充。因为符号位变成了 0,所以结果总是非负的。(译注:即便右移 0 个比特,结果也是非负的。)

    const a = -5; // 100...00101原 - 11...111010反 - 11...111011补
    a >>> 2 // 0011...1110 = 1073741822
    

    总共是有32位,中间的省略了。无符号位移最有可能在实际开发中使用的就是x >>> 0取整。

    lodash 中的 slice 方法:

    function slice(array, start, end) {
      ...
      length = start > end ? 0 : ((end - start) >>> 0)
      start >>>= 0
      ...
    }
    
    export default slice
    

    起源地下载网 » Vue3 源码中的位运算,又一个面试考点

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元