zoukankan      html  css  js  c++  java
  • 尽量不要在JS中使用位运算

    熟悉 C 或者 C++ 的同学一定对位操作符不陌生。位操作符最主要的应用大概就是作为标志位与掩码。这是一种节省存储空间的高明手段,在曾经内存的大小以 KB 为单位计算时,每多一个变量就是一份额外的开销。而使用位操作符的掩码则在很大程度上缓解了这个问题:

    #define LOG_ERRORS            1  // 0001
    #define LOG_WARNINGS          2  // 0010
    #define LOG_NOTICES           4  // 0100
    #define LOG_INCOMING          8  // 1000
    
    unsigned char flags;
    
    flags = LOG_ERRORS;                                 // 0001
    flags = LOG_ERRORS | LOG_WARNINGS | LOG_INCOMING;   // 1011

    因为标志位一般只需要 1 bit,就可以保存,并没有必要为每个标志位都定义一个变量。所以按上面这种方式只使用一个变量,却可以保存大量的信息——无符号的 char 可以保存 8 个标志位,而无符号的 int 则可以同时表示 32 个标志位。

    可惜位操作符在 JavaScript 中的表现就比较诡异了,因为 JavaScript 没有真正意义上的整型。看看如下代码的运行结果吧:

    var a, b;
    
    a = 2e9;   // 2000000000
    a << 1;    // -294967296
    
    // fxck!我只想装了个逼用左移1位给 a * 2,但是结果是什么鬼!!!
    
    a = parseInt('100000000', 16); // 4294967296
    b = parseInt('1111', 2);       // 15
    a | b;                         // 15
    
    // 啊啊啊,为毛我的 a 丝毫不起作用,JavaScript真是门吊诡的语言!!!

    好吧,虽然我说过大家可以近似地认为,JS 的数字类型可以表示 53 位的整型。但事实上,位操作符并不是这么认为的。在 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位的整数会被截断,而小数部分则会被直接舍弃。

    而反过来考虑,我们在什么情况下需要用到位操作符?使用左移来代替 2 的幂的乘法?Naive啊,等遇到像第一个例子的问题,你就要抓狂了。而且对一个浮点数进行左移操作是否比直接乘 2 来得效率高,这也是个值得商榷的问题。

    那用来表示标志位呢?首先,现在的内存大小已经不值得我们用精简几个变量来减少存储空间了;其次呢,使用标志位也会使得代码的可读性大大下降。再者,在 JavaScript 中使用位操作符的地方毕竟太少,如果你执意使用位操作符,未来维护这段代码的人又对 JS 中的位操作符的坑不熟悉,这也会造成不利的影响。

    所以,我对大家的建议是,尽量在 JavaScript 中别使用位操作符。

  • 相关阅读:
    file & iconv
    UML类图思考
    Rust PhantomData and dropck rgb
    golang recover rgb
    帮上小学的女儿写的一篇文章春夏秋冬
    SAP B1在添加物料主数据时,出现错误提示‘xxxx代码已存在’的解决方法
    SAP B1外协物料处理方法
    SAP B1外发加工件成本的处理方法(曹玉平于奥莱照明)
    SAP B1存在的BUG
    交叉表的实殃及向SQL SERVER数据库中插入数据时,出现乱码或???(问号)的解决方法。
  • 原文地址:https://www.cnblogs.com/ckAng/p/13292236.html
Copyright © 2011-2022 走看看