当使用具有高级优化的Closure编译器时,如何在javascript中保留全局变量?

时间:2011-05-28 12:29:35

标签: javascript obfuscation google-closure-compiler minify

我有自己的Javascript库,我希望通过使用带有高级优化的Google闭包编译器来缩小它。通过查看docs,我看到如何声明在库外使用的函数。

但是我找不到如何保存在我的库中声明的全局变量的方法。 Closure编译器只是删除它们,因为它认为它们从未被使用过。有人可以帮忙吗?

编辑:示例代码:

var variable_1 = true;

这是在我的库的开头全局定义的,但它从未在库本身中使用过。当它包含在某个页面中时,它在库外使用。但Closure编译器不知道,这就是它删除这些声明的原因。

3 个答案:

答案 0 :(得分:7)

闭包编译器无法删除声明为window["variable_1"] = true

的全局变量

我建议您直接向window写入全局变量,我还建议您使用字符串文字作为变量名,以便闭包不会缩小它。

答案 1 :(得分:3)

虽然您可以通过用window["varname"]替换该全局变量的所有用法来引用“true”全局变量,但“污染”全局命名空间通常不是一个好主意。 Closure Compiler旨在阻止您这样做。

CAVEAT window["varname"]var varname不一样,因为“窗口”可能并非总是非浏览器环境中的全局对象。事实上,Closure Compiler假设全局对象和“窗口”是不同的。例如,window["varname"]将汇编为window.varname而不是var varname。它们相同,但在浏览器中它们的工作方式相似。

最好创建一个全局命名空间对象,然后只导出该一个对象。所有“全局”变量都应该成为此全局命名空间变量下的属性。优点:

  1. 所有这些全局变量都重命名为较短版本
  2. 可以发生常量内联
  3. Closure Compiler无论如何都会自动“展平”命名空间,所以你的代码不会慢一些
  4. 高级混淆
  5. 您的代码也适用于非浏览器环境。请记住,“窗口”可能并不总是存在(例如,在服务器端代码中),“全局对象”可能并不总是“窗口”
  6. 如果您有全局变量,用户必须读取/设置以使用您的库,也不鼓励使用您的库。最好在全局名称空间对象上公开API,然后像往常一样通过窗口对象公开公共API:window["myLib"]["setConfig"] = myLib.setConfig

    在您的情况下,如果您在非Closure-Compiled代码的其他部分中使用了全局变量,则必须考虑:

    1. 将这些变量的声明放在Closure
    2. 编译的文件之外是否更好?
    3. 为什么不将这些变量的声明与使用它们的代码放在一起
    4. 你真的应该关闭 - 编译所有代码而不只是一部分(这可能吗?你使用另一个库吗?)

答案 2 :(得分:1)

我刚刚遇到过这个,我有自己的解决方案。

在自动执行的函数中创建整个库,将所有对象属性作为字符串(每个属性至少一次),如下所示:

(function () {
    var myLibrary = {
        'myMethod' : function () {
            ...
        }
    }
    myLibrary.myMethod['propertyOfTheMethod'] = '';
}());

从外部访问它的常用方法是将var myLibrary =放在函数前面,将return myLibrary放在它的末尾,以便将它赋给全局变量。但是该函数在全局范围内执行(因为它是自动执行的),因此我们可以使用字符串文字创建this的属性。完全如此:

(function () {
    var myLibrary = {
        'myMethod' : function () {
            ...
        }
    }
    myLibrary.myMethod['propertyOfTheMethod'] = '';
    this['myLibrary'] = myLibrary;
}());

但是,这在"use strict";下不起作用。在严格模式下获取全局变量的最佳方法是使用var global = Function('return this')();然后将变量赋值给它。