关注微信公众号:爬虫K哥,QQ交流群:808574309,继续分享高级爬虫、JS/Android逆向等技术干货!简介在分析一些站点的JavaScript代码时,通常会把比较简单的代码和函数一一列举,例如:functiona(){console.log("a")}functionb(){console.log("a")}functionc(){console.log("a")}但是稍微复杂一点的站点通常会遇到类似下面的代码结构:!function(i){functionn(t){returni[t].call(a,b,c,d)}}([function(t,e){},function(t,e,n){},function(t,e,r){},function(t,e,o){}]);这种写法在JavaScript中很常见,对于熟悉JavaScript的人来说可能会很简单,但是大多数爬虫工程师都是用Python或者Java来写代码的,看到这个语法可能会一头雾水,因为在剥离的时候经常会遇到JS加密代码,所以理解这个语法对于爬虫工程师来说非常重要。这种写法好像没有正式名称,相当于模块化编程,所以一般人都叫它webpack。上面的例子好像比较费力。简单优化:!function(allModule){functionuseModule(whichModule){allModule[whichModule].call(null,"helloworld!");}useModule(0)}([functionmodule0(param){console.log("module0:"+param)},functionmodule1(param){console.log("module1:"+param)},functionmodule2(param){console.log("module2:"+param)},]);运行上面的代码会输出module0:helloworld!,相信很容易理解变量名和函数名的大致意思应该能看懂。调用useModule(0),从所有函数中选择第一个,传递helloworld!到module0并输出它。仔细观察上面的代码,我们会发现主要用到了!function(){}()和function.call()的语法,接下来我们会一一介绍。函数声明和函数表达式在ECMAScript(JavaScript的一个标准)中,最常用的创建函数对象的方法有两种,即使用函数声明或函数表达式。ECMAScript规范明确指出,函数声明必须始终有一个标识符,也就是我们所说的函数名,函数表达式可以省略。函数声明将为函数分配一个名称,该名称将在代码执行之前加载到作用域中,因此可以在函数声明之前或之后调用函数:test("HelloWorld!")functiontest(arg){console.log(arg)}函数表达式,创建一个匿名函数,然后把这个匿名函数赋值给一个变量,这个变量只有在代码执行到函数表达式时才会被定义,所以调用函数只能是函数表达式运行后正确,否则会报错:vartest=function(arg){console.log(arg)}test("HelloWorld!")IIFE立即调用函数表达式表达式,又称自执行函数、立即执行函数、自执行匿名函数等,IIFE是一种语法,这种模式本质上是创建后立即执行的函数表达式(命名或匿名)。当一个函数变成一个立即执行的函数表达式时,表达式中的变量就不能从外部访问了。IIFE主要用于隔离作用域,避免污染。IIFE基本语法IIFE的写法非常灵活,主要有以下几种格式:1.在匿名函数前面加一个一元运算符,后面加():!function(){console.log("IAMIIFE")}();-function(){console.log("IAMIIFE")}();+function(){console.log("IAMIIFE")}();~function(){console.log("我是IIFE")}();2.在匿名函数后面加上(),然后用()围住整个:(function(){console.log("IAMIIFE")}());3、先用()围住匿名函数,然后在它后面加上():(function(){console.log("IAMIIFE")})();4、要使用箭头函数表达式,先用()把箭头函数表达式括起来,然后在它后面加上():(()=>{console.log("IAMIIFE")})()5.在匿名函数前添加void关键字,然后在上面添加(),void指定计算或运行一个表达式,但不返回值:voidfunction(){console.log("IAMIIFE")}();有时,我们可能会看到立即执行函数前后的分号,例如:;(function(){console.log("IAMIIFE")}());!function(){console.log("IAMIIFE")}()这是因为立即执行函数通常作为一个单独的模块使用,一般不会有问题,但是建议在立即执行函数之前或者之后加一个分号,这样可以与前面或后面的代码进行有效隔离,否则可能会出现意想不到的错误。IIFE传参将参数放在()最后实现传参:vartext="IAMIIFE";(function(param){console.log(param)})(text);//IAMIIFEvardict={name:"Bob",age:"20"};(function(){console.log(dict.name);})(dict);//Bobvarlist=[1,2,3,4,5];(function(){varsum=0;for(vari=0;i
