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
真值表: (都为1,值才为1)
a | b | a AND b | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 1 |
---|
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
的计算步骤:
- 将5转二进制 =
00000101
- 按位取反 =
11111010
- 发现符号位(即最高位)为1(表示负数),将除符号位之外的其他数字取反 =
10000101
- 末位加1取其补码 =
10000110
- 转换回十进制 =
-6
负数的运算,要先找出补码,然后再取反。
~-5
的计算步骤:
- 将-5转二进制 =
10000101
- 按位取反得到反码 =
11111010
- 末位加1取其补码 =
11111011
- 再次取反 =
00000100
- 转换回十进制 =
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
真值表:
a | b | a XOR b | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 0 |
---|
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
5 | -3
负数的按位或:
5
的原码 =0000101
-3
的原码 =1000011
,反码 =1111100
, 补码 =1111101
5 | -3
=1111101
- 发现符号位(即最高位)为1(表示负数),将除符号位之外的其他数字取反 =
1000010
- 末位加1取其补码 =
1000011
- 转换回十进制 =
-3
真值表:
a | b | a OR b | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 |
---|
<<(左移),>>(右移), >>>(无符号右移),
<<(左移)
左移操作符 (<<) 将第一个操作数向左移动指定位数,左边超出的位数将会被清除,右边将会补零。
const a = 5; // 00000101
a << 2 // 00010100 = 20
a << 4 = a * 24 = a * 16 = 80;
>>(右移)
该操作符会将第一个操作数向右移动指定的位数。向右被移出的位被丢弃,拷贝最左侧的位以填充左侧。由于新的最左侧的位总是和以前相同,符号位没有被改变。所以被称作“符号传播”。
const a = 5; // 00000101
a >> 2 // 00000001 = 1
>>>(无符号右移)
该操作符会将第一个操作数向右移动指定的位数。向右被移出的位被丢弃,左侧用 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
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!