網站首頁 編程語言 正文
位運算符基本使用
- 按位與(&):a & b對于每一個比特位,兩個操作數都為 1 時, 結果為 1, 否則為 0
- 按位或(|):a | b對于每一個比特位,兩個操作數都為 0 時, 結果為 0, 否則為 1
- 按位異或(^):a ^ b對于每一個比特位,兩個操作數相同時, 結果為 1, 否則為 0
- 按位非(~):~ a反轉操作數的比特位, 即 0 變成 1, 1 變成 0
0000 0000 0000 0000 0000 0000 0000 0011 -> 3 1111 1111 1111 1111 1111 1111 1111 1100 -> ~ 3 = -4
左移位<<:各二進位全部左移若干位,高位丟棄,低位補0。
0000 0000 0000 0000 0000 0000 0000 0110 -> 6 0000 0000 0000 0000 0000 0000 0001 1000 -> 6 << 2 = 24
右移位>>:各二進位全部右移若干位,正數高位補0,負數高位補1,低位丟棄
0000 0000 0000 0000 0000 0000 0000 1100 -> 12 0000 0000 0000 0000 0000 0000 0000 0011 -> 12 >> 2 = 3 負數情況: 1111 1111 1111 1111 1111 1111 1111 0100 -> -12 1111 1111 1111 1111 1111 1111 1111 1101 -> -12 >> 2 = -3
無符號右移位>>>:各二進位全部右移若干位,高位補0,低位丟棄。
0000 0000 0000 0000 0000 0000 0000 1100 -> 12 0000 0000 0000 0000 0000 0000 0000 0011 -> 12 >>> 2 = 3 1111 1111 1111 1111 1111 1111 1111 0100 -> -12 0011 1111 1111 1111 1111 1111 1111 1101 -> -12 >> 2 = 1073741821
正數計算負數:
取反后+1
+5:0101 -5:取反1010 最低位+1 = 1011,1011即為二進制的-5
負數倒推正數:同樣為取反后+1
在js中位運算的特點
- 位運算只能在整型變量之間進行運算
- js 中的Number類型在底層都是以浮點數(參考 IEEE754 標準)進行存儲.
- js 中所有的按位操作符的操作數都會被轉成補碼(two’s complement)形式的有符號32位整數
- 操作數為浮點型時,轉換流程: 浮點數 -> 整數(丟棄小數位) -> 位運算
- 操作數的大小超過Int32范圍(-2^31 ~ 2^31-1). 超過范圍的二進制位會被截斷, 取低位32bit
- 另外由于 js 語言的隱式轉換, 對非Number類型使用位運算操作符時會隱式會發生隱式轉換, 相當于先使用Number(xxx)將其轉換為number類型, 再進行位運算:
'str' >>> 0; // ===> Number('str') >>> 0 ===> NaN >>> 0 = 0
位掩碼
通過位移定義的一組枚舉常量, 可以利用位掩碼的特性, 快速操作這些枚舉產量(增加, 刪除, 比較)
const A = 1 << 0; // 0b00000001 const B = 1 << 1; // 0b00000010 const C = 1 << 2; // 0b00000100 屬性增加| ABC = A | B | C //0b00000111 屬性刪除& ~ AB = ABC & ~C //0b00000011 屬性比較 AB 當中包含 B: AB & B === B。// AB & B =>0b00000010 ===B,true AB 當中不包含 C: AB & C === 0 // AB & C =>0b00000000 === 0,true
react中的位運算
- react在涉及狀態、標記位、優先級操作的地方大量使用了位運算
標記狀態
- react源碼內部有多個上下文環境,在執行函數時經常需要判斷當前處在哪個上下文環境中
// A上下文 const A = 1; //0001 // B上下文 const B = 2; //0010 // 當前所處上下文 let curContext = 0; // 沒有處在上下文的標志 const NoContext = 0; 假設進入A的上下文 curContext |= A; //即curContext=curContext|A =>0001 判斷是否處在某一上下文中,結合按位與操作與NoContext // 是否處在A上下文中,這里為true (curContext & A) !== NoContext //curContext & A)=>0001 !==0000,所以為true,表示在A的上下文中 // 是否處在B上下文中,這里為false,和上方同理 (curContext & B) !== NoContext 離開上下文,取出標記進行恢復 // 從當前上下文中移除上下文A curContext &= ~A; //curContext=curContext& ~A,即0001&1110=0000,進行恢復 // 是否處在A上下文中,此處為false (curContext & A) !== NoContext //(curContext & A)為0000
ReactFiberLane.js
- 優先級定義
- 源碼中變量只列出了 31 位, 由于 js 中位運算都會轉換成Int32(上文已經解釋), 最多為 32 位, 且最高位是符號位. 所以除去符號位, 最多只有 31 位可以參與運算
//類型定義 export opaque type Lanes = number; export opaque type Lane = number; // 變量定義 export const NoLanes: Lanes = /* */ 0b0000000000000000000000000000000; export const NoLane: Lane = /* */ 0b0000000000000000000000000000000; export const SyncLane: Lane = /* */ 0b0000000000000000000000000000001; export const SyncBatchedLane: Lane = /* */ 0b0000000000000000000000000000010; export const InputDiscreteHydrationLane: Lane = /* */ 0b0000000000000000000000000000100; const InputDiscreteLanes: Lanes = /* */ 0b0000000000000000000000000011000; const InputContinuousHydrationLane: Lane = /* */ 0b0000000000000000000000000100000; const InputContinuousLanes: Lanes = /* */ 0b0000000000000000000000011000000; // ... // ... const NonIdleLanes = /* */ 0b0000111111111111111111111111111; export const IdleHydrationLane: Lane = /* */ 0b0001000000000000000000000000000; const IdleLanes: Lanes = /* */ 0b0110000000000000000000000000000; export const OffscreenLane: Lane = /* */ 0b1000000000000000000000000000000;
getHighestPriorityLanes
function getHighestPriorityLanes(lanes: Lanes | Lane): Lanes { // 判斷 lanes中是否包含 SyncLane if ((SyncLane & lanes) !== NoLanes) { return_highestLanePriority = SyncLanePriority; return SyncLane; } // 判斷 lanes中是否包含 SyncBatchedLane if ((SyncBatchedLane & lanes) !== NoLanes) { return_highestLanePriority = SyncBatchedLanePriority; return SyncBatchedLane; } // ... // ... 省略其他代碼 return lanes; }
getHighestPriorityLane
- react中處在越低bit位的更新優先級越高(越需要優先處理)
- 分離出最高優先級
- -lanes:表示負數的操作,即先取反然后+1
0b000 0000 0000 0000 0000 0000 0001 0001 function getHighestPriorityLane(lanes) { return lanes & -lanes; } -lanse: lanes 0001 0001 ~lanes 1110 1110 // 第一步 +1 1110 1111 // 第二步 0001 0001 // lanes & 1110 1111 // -lanes ----------- 0000 0001 若lanes為0001 0000 0001 0000 // lanes & 1111 0000 // -lanes ----------- 0001 0000
getLowestPriorityLane
- 假設 lanes(InputDiscreteLanes) = 0b0000000000000000000000000011000
- 那么 clz32(lanes) = 27, 由于 InputDiscreteLanes 在源碼中被書寫成了 31 位, 雖然在字面上前導 0 是 26 個, 但是轉成標準 32 位后是 27 個
- index = 31 - clz32(lanes) = 4
- 最后 1 << index = 0b0000000000000000000000000010000
- 相比最初的 InputDiscreteLanes, 分離出來了最左邊的1
- 通過 lanes 的定義, 數字越小的優先級越高, 所以此方法可以獲取最低優先級的 lane
function getLowestPriorityLane(lanes: Lanes): Lane { // This finds the most significant non-zero bit. const index = 31 - clz32(lanes); return index < 0 ? NoLanes : 1 << index; }
react-reconciler上下文定義
export const NoContext = /* */ 0b0000000; const BatchedContext = /* */ 0b0000001; const EventContext = /* */ 0b0000010; const DiscreteEventContext = /* */ 0b0000100; const LegacyUnbatchedContext = /* */ 0b0001000; const RenderContext = /* */ 0b0010000; const CommitContext = /* */ 0b0100000; export const RetryAfterError = /* */ 0b1000000; // ... // Describes where we are in the React execution stack let executionContext: ExecutionContext = NoContext;
scheduleUpdateOnFiber
// scheduleUpdateOnFiber函數中包含了好多關于executionContext的判斷(都是使用位運算) export function scheduleUpdateOnFiber( fiber: Fiber, lane: Lane, eventTime: number, ) { if (root === workInProgressRoot) { // 判斷: executionContext 不包含 RenderContext if ( deferRenderPhaseUpdateToNextBatch || (executionContext & RenderContext) === NoContext ) { // ... } } if (lane === SyncLane) { if ( // 判斷: executionContext 包含 LegacyUnbatchedContext (executionContext & LegacyUnbatchedContext) !== NoContext && // 判斷: executionContext 不包含 RenderContext或CommitContext (executionContext & (RenderContext | CommitContext)) === NoContext ) { // ... } } // ... }
- 在特定的情況下, 使用位運算不僅是提高運算速度, 且位掩碼能簡潔和清晰地表示出二進制變量之間的關系.
- 但是缺點也很明顯, 不夠直觀, 擴展性不好(在 js 當中的二進制變量, 除去符號位, 最多只能使用 31 位, 當變量的數量超過 31 個就需要組合, 此時就會變得復雜)
總結
原文鏈接:https://blog.csdn.net/weixin_43294560/article/details/123316506
相關推薦
- 2022-12-31 Echars 報錯: Error in created hook: “Cannot read pro
- 2022-11-24 Android開發使用Message對象分發必備知識點詳解_Android
- 2022-09-21 Oracle數據庫對象的使用詳解_oracle
- 2023-03-21 通俗易懂的C語言快速排序和歸并排序的時間復雜度分析_C 語言
- 2023-01-21 Python參數解析器configparser簡介_python
- 2022-11-01 JetPack?Compose底部導航欄的實現方法詳解_Android
- 2022-07-07 python中列表對象pop()方法的使用說明_python
- 2022-06-14 Redis高并發情況下并發扣減庫存項目實戰_Redis
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支