介绍

GCC(Google Closure Compiler)是由谷歌发布的Js代码压缩编译工具。它可以做到分析Js的代码,移除不需要的代码(dead code),并且去重写它,最后再进行压缩。

三种压缩模式

GCC提供三种压缩模式:

1)Whitespace only
2)Simple
3)Advanced

我们以这段简单的代码为例

function sayHello(name) {
alert('Hello, ' + name);
}
sayHello('binnng');

分别使用这三种压缩模式进行压缩:

Whitespace only

function sayHello(name){alert("Hello, "+name)}sayHello("binnng");

发现只是简单的去除空格换行注释。

Simple

function sayHello(a){alert("Hello, "+a)}sayHello("binnng");

Whitespace only要高端一点,在其基础上,还对局部变量的变量名进行缩短。这也是其他压缩工具所使用的压缩方式,如Uglify等,也是最为主流的压缩方式。比较安全。

Advanced

alert("Hello, binnng");

会发现,Advanced级别的压缩改变(破坏)了原有代码结构,直接输出了代码最终运行结果,可见的确是分析重写破坏,但是对代码压缩做到了极致,极大的减少了代码量。

注意的地方

正因为GCC是这样的破坏性压缩工具,所以使用起来得异常小心,稍微不规范可能就会引起压缩报错或者压缩成功后却不能正常运行。那么,如果要使用Advanced级别压缩,要注意哪些呢?

以下所有未指名级别的GCC压缩均为Advanced级别。

GCC会对变量的属性名也进行压缩

var data = {
user: "binnng",
age: "18"
}; if ("user" in data) {
alert(data.age);
}

经过Uglify压缩:

var data={user:"binnng",age:"18"};"user"in data&&alert(data.age);

经过GCC压缩:

var a={b:"binnng",a:"18"};"user"in a&&alert(a.a);

会发现GCC压缩时,将变量的属性名也缩短,代码量减少了,但是却带来了问题,会发现以上GCC压缩后的代码运行其实是不正确的。因为属性名缩短改变后,data已经不再拥有名为user的属性了。

那如何解决呢?

var data = {
user: "binnng",
age: "18"
}; if (data.user) {
alert(data.age);
}

这时候再经过GCC压缩:

alert("18");

直接输出了正确的结果。

如果不想让GCC压缩属性名,比如在Ajax请求发送给后端接口的时候,可以将属性名用双引号包裹:

var data = {
"user": "binnng",
"age": "18"
}; var ajax = function(url, data, callback) {
(new window.XMLHttpRequest()).send(data);
// ...
}; ajax("//baidu.com", data, function(res) {console.log(res)});

这样经过GCC压缩后:

(new window.XMLHttpRequest).send({user:"binnng",age:"18"});

原封不动的保留了后端需要的参数名。

全局变量要显式挂载在window下

var foo = "1234";
alert(widnow.foo);

这时候,经过GCC压缩后:

alert(window.a);

有点莫名其妙。。因为在GCC中,不再认可隐式全局变量,所以上面的代码中在GCC眼里,foo是没有挂载到window下的,所以下文的window.foo其实是未定义的。

要解决这个问题,必须将foo显式挂载到window下:

window.foo = "1234";
alert(widnow.foo);

这样经过压缩后:

window.a="1234";alert(widnow.a);

这时候可能就会疑问,为何不直接压缩成alert("1234")呢?这是因为GCC不会去除挂载在window下的变量

必要时导出变量函数等

window.btnClick = function() {
alert("clicked");
};

以上的代码经过压缩后成为:

window.a=function(){alert("clicked")};

此时,如果HTML中存在如下代码,就会报错。

<a onclick="btnClick()">点我</a>

这时候就需要导出函数

window["btnClick"] = function() {
alert("clicked");
};

用双引号包裹后,btnClick就保留了下来。在构造函数中,尤其需要注意导出,例如:

var Animal = function(name) {
this.name = name;
};
Animal.prototype.eat = function() {
alert(this.name + " is eating!");
};

以上的代码经过GCC压缩后,什么都没剩下,因为GCC认为,代码中的代码都没有执行,属于dead code。既然这么写了,那肯定是需要它,提供给别人外部调用什么的,这时候就需要这么导出:

var Animal = function(name) {
this.name = name;
};
Animal.prototype.eat = function() {
alert(this.name + " is eating!");
}; window["Animal"] = Animal;
Animal.prototype["eat"]= Animal.prototype.eat;

经过压缩后:

function a(b){this.name=b}a.prototype.a=function(){alert(this.name+" is eating!")};window.Animal=a;a.prototype.eat=a.prototype.a;

这时候,Animal这个方法成功的保留了下来。

还有,在使用JSONP方式获取服务端数据的时候,也一定要导出callback方法名:

var jsonpCb = function() {
//...
}; getScript("/api/data?callback=jsonpCb"); // 导出,否则jsonpCb会被压缩掉不能被识别
window["jsonpCb"] = jsonpCb;

所有业务代码合并压缩

a.js

var getName = function() {return "binnng"};

b.js

alert(getName());

如果单独压缩a.jsb.js就会出问题,结果会是a.js中什么都没有,b.jsgetName方法未定义(undefined)。正确的做法则是,两者合并再进行压缩。

结语

GCC的高级压缩(Advanced)非常强大,对代码压缩做到了极致,但是其对代码书写要求也比较严格,并且破坏性压缩也被很多开发者所诟病。

但是稍加注意,严格规范自身代码风格,了解GCC压缩方式原理,利用好GCC高级压缩,一定会大大减少JS的体积,从而大幅度的提升前端代码性能。

另外,GCC像其他压缩工具一样,也有GruntGulp构建组件,可以很方便的去使用它。

//原文地址:http://segmentfault.com/blog/laopopo/1190000002575760

使用Google Closure Compiler高级压缩Javascript代码注意的几个地方的更多相关文章

  1. 使用Google Closure Compiler高级压缩Javascript代码

    背景 前端开发中,特别是移动端,Javascript代码压缩已经成为上线必备条件. 如今主流的Js代码压缩工具主要有: 1)Uglify http://lisperator.net/uglifyjs/ ...

  2. Google Closure Compiler高级压缩混淆Javascript代码

    一.背景 前端开发中,特别是移动端,Javascript代码压缩已经成为上线必备条件. 如今主流的Js代码压缩工具主要有: 1)Uglify http://lisperator.net/uglifyj ...

  3. 使用Google Closure Compiler全力压缩代码(转)

    JavaScript压缩代码的重要性不言而喻,如今的压缩工具也有不少,例如YUI Compressor,Google Closure Compiler,以及现在比较红火的UglifyJS.Uglify ...

  4. Google Closure Compiler 高级模式及更多思考(转)

    前言 Google Closure Compiler 是 Google Closure Tools 的一员,在 2009 年底被 Google 释出,早先,有 玉伯 的 Closure Compile ...

  5. JavaScript代码压缩工具UglifyJS和Google Closure Compiler的基本用法

    网上搜索了,目前主流的Js代码压缩工具主要有Uglify.YUI Compressor.Google Closure Compiler,简单试用了UglifyJS 和Google Closure Co ...

  6. bootstrap-datetimepicker在经过GC(Google Closure Compiler)压缩后无法使用的解决方案

    将压缩级别由simple改成whitespace 问题就是这样之后压缩后的文件大了很多 <?xml version="1.0"?> <project name=& ...

  7. Gulp压缩JavaScript代码

    因为gulp是自动化工具,所以我们得告诉它,需要怎么做,才能达到我们的目的. 我们首先得新建一个js文件,用来编写我们的需求,以便gulp能按着我们的意愿来执行. 我将这个js文件取名叫gulpfil ...

  8. Grunt 使用(二)uglify插件压缩javascript代码

    本文在配置grunt基本环境的基础下,讲解如何使用grunt-contrib-uglify进行javascript压缩 本文只介绍了grunt-contrib-uglify插件的一种压缩方式适用于大部 ...

  9. 【Java】通过移除空行和注释来压缩 JavaScript 代码

    1. [代码]JavaScriptCompressor.java/** * This file is part of the Echo Web Application Framework (herei ...

随机推荐

  1. 避免重复造轮子的UI自动化测试框架开发

    一懒起来就好久没更新文章了,其实懒也还是因为忙,今年上半年的加班赶上了去年一年的加班,加班不息啊,好了吐槽完就写写一直打算继续的自动化开发 目前各种UI测试框架层出不穷,但是万变不离其宗,驱动PC浏览 ...

  2. wepack+sass+vue 入门教程(二)

    六.新建webpack配置文件 webpack.config.js 文件整体框架内容如下,后续会详细说明每个配置项的配置 webpack.config.js直接放在项目demo目录下 module.e ...

  3. POCO Controller 你这么厉害,ASP.NET vNext 知道吗?

    写在前面 阅读目录: POCO 是什么? 为什么会有 POJO? POJO 的意义 POJO 与 PO.VO 的区别 POJO 的扩展 POCO VS DTO Controller 是什么? 关于 P ...

  4. LeetCode-4MedianofTwoSortedArrays(C#)

    # 题目 4. Median of Two Sorted Arrays There are two sorted arrays nums1 and nums2 of size m and n resp ...

  5. [APUE]标准IO库(下)

    一.标准IO的效率 对比以下四个程序的用户CPU.系统CPU与时钟时间对比 程序1:系统IO 程序2:标准IO getc版本 程序3:标准IO fgets版本 结果: [注:该表截取自APUE,上表中 ...

  6. Python标准模块--Iterators和Generators

    1 模块简介 当你开始使用Python编程时,你或许已经使用了iterators(迭代器)和generators(生成器),你当时可能并没有意识到.在本篇博文中,我们将会学习迭代器和生成器是什么.当然 ...

  7. 玩转ajax

    1.什么是ajax? Ajax 是 Asynchronous JavaScript and XML(以及 DHTML 等)的缩写. 2.ajax需要什么基础? HTML 用于建立 Web 表单并确定应 ...

  8. App 审核由于 IPv6 网络问题被拒

    昨天 提交App Store 的时候被拒了 We discovered one or more bugs in your app when reviewed on iPhone running iOS ...

  9. 从贝叶斯到粒子滤波——Round 1

    粒子滤波确实是一个挺复杂的东西,从接触粒子滤波到现在半个多月,博主哦勒哇看了N多篇文章,查略了嗨多资料,很多内容都是看了又看,细细斟酌.今日,便在这里验证一下自己的修炼成果,请各位英雄好汉多多指教. ...

  10. 初探java中this的用法

    一般this在各类语言中都表示“调用当前函数的对象”,java中也存在这种用法: public class Leaf { int i = 0; Leaf increment(){ i++; retur ...