UglifyJS为了极致的压缩你的代码,用了哪些奇技淫巧?

「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战

UglifyJS 为了极致的压缩你的代码,用了一些有趣的 "奇技淫巧",这里面或许有你从来没听过的语法呢。

替换变量名

let randomNumber = Math.random();
let randomNumber1 = Math.random();
console.log(randomNumber, randomNumber1);

// 压缩后
var n=Math.random(),o=Math.random();console.log(n,o)
复制代码

这个是最基础的,无论你的变量名多长,都给你替换成一个字符 n,o,p,q.....,单个字母用完了就 n1,o1

立即执行函数

(function (){console.log(1)})()

// 压缩后
!function (){console.log(1)}()
复制代码

我本是第一种写法,uglify 给我替换成了第二种(当然更短一点)。其实括号和 ! 号的作用都是将 funtion 的部分转成一个表达式,而不再是申明。这样就能立即执行,同理~ +都可以做到。

一个字符之差也要优化一下,简直丧心病狂

函数置顶以&逗号运算符

function foo (){} 这种形式的代码都会被放到模块的最顶端。当然这是一种规范,后来发现还有另外一个作用就是方便后面的代码合并。 比如 我们这样定义:

var self=this;
function a(){console.log(1);}
self.a=a;
function b(){console.log(2);}
self.b=b;
a()
b()
return self;

// 压缩后
var n=this;
function o(){console.log(1)}
function t(){console.log(2)}
return n.a=o,n.b=t,o(),t(),n
复制代码

注意到最后的 n 不能漏了,return 会以最后一个表达式的结果为准。

,运算符会返回 , 后面的执行结果,详情请看这篇文章 二八原则:JavaScript中逗号操作符进阶用法

bool值替

会使用 !0 来代替 true,使用 !1 来代替 false,是不是代码变短了呢?

不愧是 奇技淫巧

console.log(true);
console.log(false);

// 压缩后
console.log(!0),console.log(!1);
复制代码

逗号运算符随处可见

if

return 前置:

比如我的原函数大概是这样。压缩后成了这样:

function load() {
    if (t) {
        x = false;
        log("error");
        return;
    }
    console.log("22")
}

//压缩后
function load(){if(t)return x=!1,void log("error");console.log("22")}
复制代码

return 提前了,后面多了一个 void。 这是为什么呢。 没有大括号,if的四段代码变成了一句话。void 的在这里的作用是抹掉函数的返回值。因为本来的这个 if 是没有返回值的 。如果这个时候 log 方法带有返回值。那么调用 load 就会拿到这个返回值。这会产生干扰,违背了原函数的本意。所以用 void 抹掉了。

短路

function foo() {
    if (!x) {
        return;
    }
    console.log("doA");
    console.log("doB");
}

// 压缩后 
function foo(){x&&(console.log("doA"),console.log("doB"))}
复制代码

这样蛮不错的。同理:

if(x&&y){
 doa();
 dob(); 
}
 doc();  

-->    x&&y&&(doa(),dob()),doc()
复制代码

原本四行变成了一行代码。

为了合并一行,这也行?

console.log("doA");
console.log("doB");
if (x>0) {
	console.log("true");
}

// 压缩后,合并成这样
if (console.log("doA"), console.log("doB"), x > 0) console.log("true");
复制代码

平时这么写可能不太友好,重点是在if语句中,最后一句才是判断句。结合之前的return。想必对逗号语句有了深刻的认识。

throw也不放过

if (errMsg) {
    util.triggerCallback(fail, "模型验证错误");
    throw Error(errMsg);
}

// 压缩后是这样的
if(errMsg)throw util.triggerCallback(fail,"模型验证错误"),Error(errMsg);
复制代码

调换了语句的顺序,把 throw 看成 return 就明白了。

丧心病狂

if else

会替换成三元表达式 a?b:c ,最基本的优化。

if(a) {
    console.log(1);
} else {
    console.log(2);
}

// 压缩后
a?console.log(1):console.log(2);
复制代码

数字处理

整百整千的会处理成科学计数。

例如: 1000 -->1e3 。

while

var offset = 0;
while (true) {
    if (offset >= bufferLength) {
        break;
    }
}

// 会替换成这样
for(var offset=0;;)if(offset>=bufferLength)break;
复制代码

不错,确实节省了一行

上面只是方向一下自己觉得有趣的东西,也可以在开发者串起来使用,当然不是追求所有代码都写成一行,这样可读性比较差,另外可能你下次看压缩代码就不那么费劲了。

猜你喜欢

转载自juejin.im/post/7055593143474847757