js实用小技巧

1.位运算

~符

  ~是按位取反的运算符,得到的结果是它的相反数减一(和补数取模有关,感兴趣可以了解下)。一般在可能返回-1的函数中比较好用。-1的相反数刚好是0,转成布尔就是false。所以:

if(arr.indexOf(a)!==-1){...}
//等价于
if(~arr.indexOf(a)){...}

~~符

~~可以用来取整,因为位运算会舍弃浮点数:

~~1.23 === 1 //true
~~-1.23 === -1 //true

当然其它的位运算也可行,只要经过运算能复原原来的数,例如:

//y|0 === int(y)
(1.23|0) === 1 //true
(-1.23|0) === -1 //true
//x^y^x = int(y);x可以换成任何整数,这种写法太花哨,leader可能会打回来,哈哈
(111^1.23^111) === 1 //true
(111^-1.23^111) === -1 //true

有了快速取整就有了判断一个数字是不是整数的方法:

function isInteger(num){return num === ~~num;}//判断是不是整数

但是对于比较大的浮点数,这种取整方式也会有问题:
在这里插入图片描述
因为取整的原理是进行位运算会强制转换数据类型,该整数不能大于2**31-1(切记切记)。所以一般不要用在可能出现大数的环境中,不然bug找得你头秃。

&符

  &是按位与,常用来判断奇偶。我们平时用取模判断奇偶可能还会遇到小数的情况,导致判断出问题:

12.3%2 //0.3000000000000007

这个时候判断等于1或者0都会有问题,而使用&则比较方便:

12.3&1 === 0//偶数最后一位为0,二进制表示1100
13.3&1 === 1//奇数数最后一位为0,二进制表示1101

lowbit运算
在算法中我们树状数组进行查询和更新,通常会访问lowbit节点。
表示最低位1和后面0组成的数字,比如说6的二进制是110那么lowbit就是最后的10组成的数也就是2。

x&-x

移位

  <<和>>是算术移位,将不会改变符号位。
  >>>是逻辑右移,符号位也会跟着移动。JavaScript没有实现逻辑左移。

5>>1//2 因为5的二进制是101 右移一位后变成了10二进制就是2,相当于除以二向下取整
2<<1//4 2的二进制是10 左移一位后就就变成了100二进制就是4,相当于乘以2 
-1>>>1//2147483647 -1的补码表示为0XFFFFFFFF全为1,逻辑移位后符号位就是0也就是正数,且全1,也就是32位有符号能表示的最大正数了

同样位移运算对于超出32位整数的值会出现问题:
在这里插入图片描述
那么创建一个稳定的系统一定要在合适的场景使用位运算,如果滥用将会出奇怪的bug。

2.实用函数

function UUID (){//生成UUID,唯一id,几乎无碰撞。ps:用来当dom便历的key可是很合适啊
    var temp_url = URL.createObjectURL(new Blob());
    var uuid = temp_url.toString(); // blob:https://xxx.com/b250d159-e1b6-4a87-9002-885d90033be3
    URL.revokeObjectURL(temp_url);
    return uuid.substr(uuid.lastIndexOf("/") + 1);
}

function timeFormate(timeStr,formStr){//时间序列化,非常方便格式转化
    if(!timeStr){return ""}
    let time=new Date(timeStr),str=formStr;
    if(time!=="Invalid Date"){
    str=str.replace("yyyy",time.getFullYear());
    str=str.replace("MM",(time.getMonth()+1).toString().padStart(2,"0"));
    str=str.replace("dd",time.getDate().toString().padStart(2,"0"));
    str=str.replace("hh",time.getHours().toString().padStart(2,"0"));
    str=str.replace("mm",time.getMinutes().toString().padStart(2,"0"));
    str=str.replace("ss",time.getSeconds().toString().padStart(2,"0"));
    }
    return str;
};
console.log(timeFormate(new Date(),"yyyy-MM-dd hh:mm:ss"));
//2021-11-24 21:26:56
console.log(timeFormate(new Date(),"yyyy-MM-dd"));
//2021-11-24
console.log(timeFormate(new Date(),"yyyy年MM月dd日hh时mm分ss秒"));
//2021年11月24日21时26分56秒
console.log(timeFormate(new Date(),"yyyy/MM/dd hh:mm:ss"));
//2021/11/24 21:26:56
function openFile(accept){//打开文件选择,不需要额外dom布局
    return new Promise((rs)=>{
        let fileInput = document.createElement("input");
        fileInput.setAttribute("display","none");
        fileInput.setAttribute("type","file");
        fileInput.setAttribute("accept",accept);
        fileInput.addEventListener("change",(e)=>{
            rs(fileInput,e);//e中不包含target,所以需要直接用创建的元素获取传入的文件
        });
        fileInput.click();//无交互时自动点击无效.
    });
}

在这里插入图片描述

3.冷知识

  (1)我们对es6的Set还是停留在去重上,但是它还有个重要的作用就是保存引用。Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。这就相当于能存储指针,对我们操作链表和树有很大的帮助。比如说我们要遍历存储链表每个节点的引用:

 //head是一条链表的头部
 let arr = [];
 for(;;){
    if(head===null){break;}
    let node = head;
    arr.push(node);
    head = head.next;
 }

本意是想存储链表每个节点的引用,但是没法达到效果,因为node并不会新建一个引用还是指向head,head一变所有的数组存的node都会变,根本达不到效果。而set就能实现我们想要的效果:

let set = new Set;
for(;;){
      if(head===null){break;}
      set.add(node);
      head = head.next;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值