JavaScript?编写枚举的最有效方法分享
在JavaScript中,我们常常需要对一些固定选项进行标记。源码移位例如,位正我们需要统计员工的数源技术栈,目前我们需要标记的码左技术有 CSS、JavaScript、正数左移筹码峰起跑线指标源码HTML、源码移位WebGL。位正以往,数源我们可能会这样写枚举:
const SKILLS = { CSS: 1 ,码左 JS: 2, HTML: 3, WEB_GL: 4}
最近,我在学习Vue源码时,正数左移发现了一个高效使用枚举的源码移位技巧。这种方法可以让我们更高效地管理这些标记。位正我们可以这样定义枚举:
const SKILLS = { CSS: 1 ,数源 JS: 1 1, HTML: 1 2, WEB_GL: 1 3}
左移运算符(<<)将第一个操作数左移指定位数。向左移动的码左多余位被丢弃。零位从右侧移入。例如:二进制的 1 是 ,左移一位是 ,即十进制的 2。如果我们将其移动两位,渔泡网源码它将变为 ,即十进制的 4。如果我们将其移动三位,它将变为 ,即十进制的 8。如果我们将其移动 N 位,它将变为 2^N在十进制。
按照上面的方法定义好枚举后,我们可以这样使用:
const SKILLS = { CSS: 1 , JS: 1 1, HTML: 1 2, WEB_GL: 1 3}
// 使用这个值来存储用户的技能栈let skills = 0
// 添加用户的技能function addSkill(skill) { skills = skills | skill}
addSkill(SKILLS.CSS)
addSkill(SKILLS.JS)
// 如果这个值不为 0,表示用户掌握了该技术console.log('他是否掌握了CSS', (skills & SKILLS.CSS) !== 0)
console.log('他是否掌握了JavaScript', (skills & SKILLS.JS) !== 0)
console.log('他是否掌握了WebGL', (skills & SKILLS.WEB_GL) !== 0)
这里需要注意,| 是按位或运算符,它在每个操作数的对应位为 1 的每个位位置返回 1。例如:const a = 5; // const b = 3; // console.log(a | b); // // 预期输出:7
如何理解这段代码?在 JavaScript 中,整数存储在 4 个字节中,即 位。第一个代表正负,后面的 位代表数字。当我们用二进制表示 1, 1 2 时,它们看起来像这样:我们定义的饭卡商城源码枚举变量只有一个二进制格式的1,并且占据不同的位置。当我们向技能添加枚举选项时,我们使用 skills | skill。假设现在我们需要添加的技能是 SKILLS.CSS,那么在执行过程中,就是:
我们可以发现,在技能中,SKILLS.CSS 对应的位置会变成1。反之,那么我们可以通过查看 skills & SKILLS.CSS 的结果是否为 0 来判断技能中是否存在 SKILLS.CSS。顺便说一句,这里我们也可以发现这个技巧有个缺点,就是枚举项不能超过 个。
我们为什么要使用这个技巧?答案很简单,这样的代码运行起来更高效。CPU 中有直接对应位操作的指令,因此效率更高。我们也可以做一个性能测试。如果我们不使用按位运算,网叶源码而是使用传统的方法(数组或映射)来实现,那么代码如下。
Array 方法:
const SKILLS = { CSS: 1 , JS: 1 1, HTML: 1 2, WEB_GL: 1 3}
// 使用数组来存储用户的技能栈let skills = []
function addSkill(skill) { if (!skills.includes(skill)) { // 避免重复存储 skills.push(skill) }}
addSkill(SKILLS.CSS)
addSkill(SKILLS.JS)
skills.includes(SKILLS.CSS)
skills.includes(SKILLS.JS)
skills.includes(SKILLS.WEB_GL)
Map 方法:
const SKILLS = { CSS: 1 , JS: 1 1, HTML: 1 2, WEB_GL: 1 3}
// 使用映射来存储用户的技能栈let skills = { }
function addSkill(skill) { if (!skills[skill]) { skills[skill] = true }}
addSkill(SKILLS.CSS)
addSkill(SKILLS.JS)
skills[SKILLS.CSS]
skills[SKILLS.JS]
skills[SKILLS.WEB_GL]
这是 jsbench.me 的性能测试:使用按位枚举,性能明显更高。
C#移ä½è¿ç®
移ä½è¿ç®(shifting operationï¼æ¯C#ä¸ä¸ç§ç¹æ®çè¿ç®ï¼å ¶åçæ¯æ ¹æ®æ°å¼åå¨å¨è®¡ç®æºå åä¸ä»¥äºè¿å¶çæ åï¼è¿è¡å移æè å移è¥å¹²ä½çç®æ³ãæ ¹æ®é¢ç®æ¥çï¼æ 符å·ä½çæ°å移å¨âå·¦âãâå³âæ以ä¸è§å¾ï¼
1ï¼å·¦ç§»ï¼å°æ¯ä¸ªäºè¿å¶çæ°åå¾å·¦è¾¹ç§»å¨è¥å¹²ä½ï¼è¥å¹²ä½ï¼ç¬¦å·â<<âåé¢çæ°åï¼ä¸è¶³ä»¥0è¡¥å ï¼ã
2ï¼å³ç§»ï¼å°æ¯ä¸ªäºè¿å¶çæ°åå¾å³è¾¹ç§»å¨è¥å¹²ä½ï¼è¥å¹²ä½ï¼ç¬¦å·â>>âåé¢çæ°åï¼ä¸è¶³ä»¥æé«ä½çæ°åè¡¥å ï¼ã
ä¸é¢ç»åºå ·ä½ä¾åï¼
ãä¾ã计ç®2<<2å2>>2ï¼
å¨è®¡ç®æºä¸ï¼æ£æ´æ°2çæºç ï¼åç ï¼è¡¥ç ï¼ ï¼å¾å·¦è¾¹æ¯ä¸ªæ°å移å¨2ä½ä¹åï¼æé«ç两ä½æº¢åºï¼ä¸¢å¼ï¼ï¼åå 为符å·ä½ï¼æé«ä½ä¸º0ï¼ï¼å æ¤è¡¥å 两个0ï¼åæ =>8.
åä¹ï¼ å³ç§»å¨2为å»æå³è¾¹ç两个æ°åï¼å¨æé«ä½ä¸æ·»å 两个0ï¼åæ =>0
ãéè¦ç»è®ºã
1ï¼å·¦ç§»åå³ç§»nä½ï¼ç¸å½äºå»æåé¢ååé¢å¯¹åºçè¥å¹²ä½ï¼åè¡¥å ã
2ï¼å½å·¦ç§»å¨æ¯2çæ¶åï¼å¯ä»¥çææ¯æ个æ°Ã2çn次æ¹ï¼åä¹é¤ä»¥2çn次æ¹ã
算术移位和逻辑移位详解
大部分C编译器中,使用移位实现代码比调用乘除法子程序生成的代码效率更高。
整理Java源码时,发现一些位运算操作,移位运算的重要性得以显现。不整理不知,一整理则深感其奥妙。
移位运算,即是将数值向左或向右移动,对于十进制而言,实现放大或缩小十倍的效果;对于二进制而言,则是放大两倍或缩小两倍。
整数乘除法在C/C++中有时会犯错,因此理解移位操作至关重要。
直接移位的小型书店源码数据类型包括:char、short、int、long、unsigned char、unsigned short、unsigned int、unsigned long,而double、float、bool、long double则不能进行移位操作。
对于有符号数据类型,如char、short、int、long,左移时,负数的符号位始终为1,其他位左移,正数所有位左移。右移时,负数取绝对值右移,再取相反数;正数所有位右移。
无符号数据类型,如unsigned char、unsigned short、unsigned int、unsigned long,移位操作使用<< 和 >> 操作符即可。
逻辑移位操作不考虑符号位,移位结果仅为数据位的移动。左移时,低位补0,右移时,高位补0。
算术移位操作则考虑符号位。对于正数,无论左移还是右移,最高位补0。对于负数,左移时高位补1,右移时高位补1。
算术移位中,符号位会跟随整体移动,以保持符号的正确性。例如,正数左移时补0,负数左移时补1。
逻辑移位适用于所有数据类型,而算术移位则需考虑符号位,以保持数值的正确性。
java提供了三种位移运算符:<<(左移)、>>(带符号右移)和>>>(无符号右移)。
移位操作是高效计算的基础,理解其原理有助于提高编程效率。
补码怎么算
1、正数的补码表示:正数的补码 = 原码
负数的补码 = { 原码符号位不变} + { 数值位按位取反后+1}or
= { 原码符号位不变} + { 数值位从右边数第一个1及其右边的0保持不变,左边安位取反}
以十进制整数+和-为例:
+原码 = _b
+补码 = _b
-原码= _b
-补码= _b
2、纯小数的原码:
纯小数的原码如何得到呢?方法有很多,在这里提供一种较为便于笔算的方法。
以0.为例,通过查阅可知其原码为0.___b。
操作方法:
将0. * 2^n 得到X,其中n为预保留的小数点后位数(即认为n为小数之后的小数不重要),X为乘法结果的整数部分。
此处将n取,得
X = d = ___b
即0.的二进制表示在左移了位后为___b,因此可以认为0.d = 0.___b 与查询结果一致。
再实验n取,得
X = d = __b 即 0.d = 0.__b,在忽略位小数之后的位数情况下,计算结果相同。
3、纯小数的补码:
纯小数的补码遵循的规则是:在得到小数的源码后,小数点前1位表示符号,从最低(右)位起,找到第一个“1”照写,之后“见1写0,见0写1”。
以-0.为例,其原码为1.___b
则补码为:
1. ___b
当然在硬件语言如verilog中二进制表示时不可能带有小数点(事实上不知道哪里可以带小数点)。
4、一般带小数的补码
一般来说这种情况下先转为整数运算比较方便
-.为例,经查询其原码为_.___b
笔算过程:
-. * 2^ = - = _____b,其中小数点在右数第位,与查询结果一致。
则其补码为_____b,在此采用 负数的补码 = { 原码符号位不变} + { 数值位按位取反后+1}方法
5、补码得到原码:
方法:符号位不动,幅度值取反+1 or符号位不动,幅度值-1取反
-.补码 = _(.)___b
取反= _(.)___b
+1 = _(.)___b 与查询结果一致
6、补码的拓展:
在运算时必要时要对二进制补码进行数位拓展,此时应将符号位向前拓展。
-5补码 = 4'b = 6'b_
ps.原码的拓展是将符号位提到最前面,然后在拓展位上部0.
-5原码 = 4‘b’ = 6'b_,对其求补码得6'b_,与上文一致。
扩展资料:
计算机中的符号数有三种表示方法,即原码、反码和补码。三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位,三种表示方法各不相同。
在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理。
此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。
2024-12-23 06:44
2024-12-23 06:35
2024-12-23 06:07
2024-12-23 05:48
2024-12-23 04:52