Fork me on GitHub

你没见过的骚操作

 有时候我们会在一些地方看到令人眼前一亮的代码,这里并不是指设计模式或者可读性、维护性那些如何精妙而是指这代码操作你没用过!

带标签的模板字符串

  先说是什么:标签使我们可以用函数解析模板字符串。标签函数的第一个参数包含一个字符串值的数组(其中的元素由模板剔除表达式后的字符串组成),其余的参数与表达式相关;

1
2
3
function tag(strings) {
console.log(strings);
}

  这里的标签函数只有一个入参,所以输出的是包含这个字符串的数组,并且该数组内还有一个raw属性,我们可以通过该属性访问模板字符串的原始字符串。另外String.raw()创建原始字符串和使用默认模板函数和字符串连接创建是等价的:

1
2
3
4
5
6
7
8
var str = String.raw`Hi\n${2+3}!`;
// "Hi\n5!"

str.length;
// 6

str.split('').join(',');
// "H,i,\,n,5,!"

  如果是多参数的情景:

1
2
3
4
5
6
7
function tag(stringsArr, ...args) {
console.log(`字符串(排除表达式)数组:`, stringsArr);
// 剩余传参 分别为模板中的表达式
for (let item of args) {
console.log(item);
}
}

  从输出结果中我们可以发现,第一个字符串数组内的元素是将模板字符串以表达式为分界符隔开的元素组成的,比如${temp}前是hhhh,像${temp2}后,没有跟随其他元素,则会提供空串给字符串数组。其后的传参则由模板中的表达式组成;

~操作符与~~操作

~操作符(非)

  在《你不知道的JavaScript》中册中有提及~操作符的使用,首先~属于位运算操作符,而位运算符只适用于32位整数,所以它会强制操作数以32位的格式来操作(通过抽象ToInt32实现,ToInt32会先执行ToNumber),所以它可以将类型转化为Number

  ~操作符能够用来屏蔽方法的技术细节:首先~非运算符等价于一个基本转换取反加一,所以有这样一个等式~x <=> -(x+1),可以联想到什么场景呢,比如判断字符串中是否存在某字符,str.indexOf(x) === -1就可以转换成~str.indexOf(x) === 0

~~操作

  ~~能够先将类型转为Number再进行小数位截断,第一个~先执行ToInt32反转字位,第二个~再反转回去得到原本的ToInt32结果,亦可以理解为小数是64位后32位的,经两次操作后被截断。

a标签之我很秀

  可以通过为a标签赋值href属性,来访问URL特性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function parseURL(url) {
var a = document.createElement('a');
a.href = url;
return {
host: a.hostname,
port: a.port,
query: a.search,
params: (function(){
var ret = {},
seg = a.search.replace(/^\?/,'').split('&'),
len = seg.length, i = 0, s;
for (;i<len;i++) {
if (!seg[i]) { continue; }
s = seg[i].split('=');
ret[s[0]] = s[1];
}
return ret;
})(),
hash: a.hash.replace('#','')
};
}

&1 判断整数奇偶性

1
2
3
let isOdd = num => !!(num & 1);
isOdd(3); // true
isOdd(2); // false

  以上原理很简单,主要从两方面理解:第一,整数的二进制转换。偶数情况下,最后一位都是0,奇数则都是1;第二与1进行&位运算等价于和最后一位为1的二进制进行与操作,高位补0,所以综合这两点其实就是看最后一位运算结果是0还是1(前面位都是0,与了也是0,略去),根据前面的奇偶最后一位特点可知,奇数时返回1,偶数返回0!!就是转布尔类型,并且在语义上保持一致(比如此处我就是判断是奇数返回,最终布尔转换就是true),综合得到上述功能代码。