竹笋

首页 » 问答 » 灌水 » JS有哪些变态语法,你知道吗
TUhjnbcbe - 2023/1/12 22:09:00
北京白癜风医院哪家最好 http://pf.39.net/bdfyy/bjzkbdfyy/

JS作为一门如此灵活的语言,自然在编码时给我们带来了很多方便,但方便的同时,也衍生出了很多变态的语法,下面我们来梳理一些常见的变态语法,希望你下次在某位大牛的代码中看到这样的东西,不要惊掉下巴。

NO.1

 Number.prototype.add=function(n){


  returnthis+n;

}

2["add"]()

最后一句话是什么玩意儿?好像没看懂呢?我们来运行一下看看

我擦?它居然执行了?结果是5,看上去似乎对2和做了加法。

不是说变量名不能数字开头么?这是怎么回事?浏览器抽风了?

实际上js有很多不能说的秘密,其中一个就叫做自动装箱,这是引用java里的叫法。也就是说,当我们试图2[“add”]的时候,这个数字2已经不再是2了,它被自动转换成了Number对象,跟java中的包装类型是一个意思。

等价于这样写:

newNumber(2)


  而对象是可以通过[“prop"]这种形式来获取属性的,于是我们就不难推理了


  2["add"]相当于newNumber(2).add


  最终变成


  newNumber(2).add();


  结果是5

NO.2

+function(){;}()

这又是个什么玩意儿?函数前面带个+号?这难道是自动类型转换?等等,里面是个;号?后面还有一对()?

先不要着急惊讶,其实还有很多,例如:

 -function(){;}()


  !function(){;}()


  ~function(){;}()


  voidfunction(){;}()


  newfunction(){;}()


  deletefunction(){;}()


  vari=function(){;}()


  1function(){;}()


  0

function(){;}()


  1function(){;}()


  1

function(){;}()


  1^function(){;}()


  1,function(){;}()

我靠!这些丧尽天良的写法是谁发明的?!你给我站出来,我保证不打死你!

接下来说说它的原理吧

首先;号本身也是一条语句,相信大多数同学应该是知道的,就不多说了。其次,一个函数的自调用,如果写成这样:

错误的原因在于,函数声明和函数调用是不可以混在一起的,所以通常的写法是:

这并不是把函数当成了一个整体来运行,这里其实还有一个不能说的秘密

()这个符号,在js里是运算符。(A)的结果是返回表达式A

所以它的出现,让这个匿名函数从声明变成了执行,也就是编译期间浏览器不会提前准备它,自然就没有语法错误。而5分钟前我们看到的那些丧心病狂的写法,其实原理都一样,通过运算符把声明变成执行。当然这些符号都不会影响函数的正常执行结果。

但是问题又来了,这种泯灭人性的写法,现在居然还挺常见的,例如:

没错,这就是著名的bootstrap的js源码,连它都是这么写的,莫非真有什么好处?

通过在网上查询大量的资料,我还真发现有人专门对此做了研究,将上面这些写法全部在各个浏览器中间做了压力测试,发现+function(){;}()执行速度最快,比(function(){})()要快出好几倍

而newfunction(){;}()执行速度最慢。

不过为了追求效率而把代码写成这样到底值不值,那只能你自己去判断了。

NO.

!!a

!!a实际上等价于a

false

由于js中所有的内容都是可以跟布尔类型互换的,这也是js特别让人费解的地方,比如

if(window.VBArray){…}

可以用来判断IE浏览器,因为对象存在时,等价于true,undefined等价于false,但是!很多时候我们判断一个属性是否存在,并不需要马上作出反应,而是将结果告知他人,比如说有个函数,test(hasSuperman),函数规定调用时需要传入一个布尔类型,告知它superman是否存在,你可能会这样写:

 if(window.superman){


  test(true);


  }else{


  test(false);


  }


  但你最好不要这么写:


  test(window.superman);

因为你并不知道test函数内部发生了什么,所以很难预料会不会产生错误,因此最好的写法是这样:

test(!!window.superman);

通过两次取反,保证了值没有变化,但类型已经被转为了布尔类型。好吧,似乎这么写还有点道理。

NO.4最短IE(6,7,8)判定

if(!-[1,]){

  //判断IE6,7,8


  }

它的原理实际上是利用了IE的bug。

当我们写下一个数组[1,].length

在IE中[1,].length-------2

在非IE中[1,].length-------1

当我们试图打印[1,],相当于调用toString()方法

在IE中[1,]-------"1,"

在非IE中[1,]-------"1"

当我们给它加上负号-[1,]

在IE中-[1,]-------NaN

在非IE中-[1,]--------1

当我们对它进行取反!-[1,]

在IE中!-[1,]-------true

在非IE中!-[1,]-------false

这样我们就可以判断是否为IE浏览器了,这个bug一直到IE9之后才消失的。

好了,这次的变态语法就先讲这么多,以后碰到更新鲜的再来给大家更新,拜拜。

在组织面向对象代码的时候我们通常使用的语法是:

 functionSwiper(){


  }


  原型编程时我们往往会因为语言的无奈写成这样的:


  Swiper.prototype.init=function(){}


  Swiper.prototype.render=function(){}


  ...

这样写丑陋且麻烦,那么如何让我们的代码变得更漂亮,更好用那?对于JS有一定了解的童鞋可能会这么写,兼容性良好且可以节省大量的代码。

 Swiper.prototype={


  constructor:Swiper,


  init:function(){


  },


  render:function(){


  }


  ....


  }

这样组织看起来工整一点但是还会存在不少莫名其妙的属性constructor是个啥,好像没啥用啊,那么如果我们在项目中加入了类似jQuery这样的类库,我们的代码就可以变得更加简练,类似于这样

 .extend(Swiper.prototype,{


  init:function(){


  },


  render:function(){


  }


  })

但是受限于语法,没法让方法看起来很很清爽,而且要引入一个庞大的类库,那么我们在项目构建时使用babel这样的编译工具,我们可以写成

 Object.assign(Swiper.prototype,{


  Init(){


  },


  render(){


  }


  })

现在你的代码可以无需任何类库,变得漂亮,优雅。甚至无需使用class关键字就可以让我们的代码变得清晰、耐看,有逼格。

说完了面向对象这个大事再跟大家普及两个极其方便的ES6新特性。

一行式数组去重:

 vararr=[1,1,2,,2,,4,5,6,7]


  arr=Array.from(newSet(arr));

ok数组去重完毕,不再用一大堆逻辑代码处理数组中的重复,不可谓不”变态”

让我们的HTMLCollection可以使用forEach,map,filer...等遍历属性:

当我们选择一组元素想要遍历的时候我们在es5中往往需要非常恶心的for循环语法:

例如:

 vardomlist=document.querySelector(“.list”);


  我们需要使用非常恶心的for循环


  for(vari=0;idomlist.lenght;i++){


  domlist.....


  }


  恶心的让人欲仙欲死,那么如何让这段代码变得优雅那?


  domlist=Array.from(domlist)


  domlist.forEach(dom={


  dom....


  })

怎么样,是不是代码上了一个台阶的赶脚。

相关推荐:

41个常用Git命令清单(建议收藏)

什么是JavaScript,它能做什么

11个杀手级JavaScript单行代码

前端学习路线图(完整版)

1
查看完整版本: JS有哪些变态语法,你知道吗