【问题标题】:Make Closure Compiler merge several object property declarations as one big literal使 Closure Compiler 将多个对象属性声明合并为一个大字面量
【发布时间】:2012-09-30 17:13:48
【问题描述】:

我将我的代码分成几个文件,然后运行一个脚本来合并和编译它们(使用ADVANCED_OPTIMIZATIONS)。大部分功能在单个对象的原型中实现。

所以当合并时,它可能看起来像这样:

(function(){

/** @constructor */ function MyConstructor() {};

MyConstructor.prototype = {};

MyConstructor.prototype['foo'] = function() { alert('foo'); };
MyConstructor.prototype['bar'] = function() { alert('bar'); };
MyConstructor.prototype['baz'] = function() { alert('baz'); };

window['MyConstructor'] = MyConstructor;

}());

如果您像这样将该代码放入Closure Compiler,则输出如下(打印精美):

function a() {
}
a.prototype = {};
a.prototype.foo = function() {
  alert("foo")
};
a.prototype.bar = function() {
  alert("bar")
};
a.prototype.baz = function() {
  alert("baz")
};
window.MyConstructor = a;

问题是,我是否可以通过某种方式告诉 Closure Compiler,可以将所有这些合并到单个对象字面量中,即使中间有代码(在此示例中)没有,但可能有),所以无论如何,它都会编译成一个大对象字面量?

这里有几个解决方案,以及为什么它们对我不起作用:

  • 解决方案 1: 只需将它们声明在一个大对象字面量中即可。
    不起作用因为我将代码放入多个文件中,并且我打算让用户使用可以在编译之前删除其中的一些(如果他们不需要的话)。对象字面量有逗号分隔符,这会使这成为一场噩梦。
  • 解决方案2:声明对象之外的所有功能(作为闭包中的私有变量),并将它们附加到最后的简化对象字面量中,该字面量仅包含对属性的引用(例如{'foo':foo,'bar':bar,'baz':baz} )。
    行不通,因为如前所述,我们的想法是创建模块化的东西,删除一个文件会使引用中断。

我对想法持开放态度!


编辑:有些人可能认为 Closure Compiler 无法做到这一点。它可以做到这一点以及更多,只是它态度不好,喜欢做就做。

将此输入到闭包中:

(function(){

var MyConstructor = window['MyConstructor'] = function() {};

var myProto = {
    'foo': function() { alert('foo'); },
    'bar': function() { alert('bar'); }
};

myProto['baz'] = function() { alert('baz'); };

MyConstructor.prototype = myProto;

}());

结果是:

(window.MyConstructor = function() {
}).prototype = {foo:function() {
  alert("foo")
}, bar:function() {
  alert("bar")
}, baz:function() {
  alert("baz")
}};

看到了吗?但是,这是代码非常脆弱,如果稍微修改一下,它可能会编译成完全不同的东西(而且不是那么好)。例如,即使是中间某处的变量赋值也可能导致它输出非常不同的结果。换句话说,这不起作用(除了这种情况)。


编辑 2:jsperf。 Chrome 中的大对象字面量更快(与其大小成正比)。


编辑 3: Closure Compiler bug report.

【问题讨论】:

  • @wvxvw Closure 与常规的缩小器非常不同,它实际上是一个编译器。它所做的事情远远超出了其他人所做的事情,至少在 ADVANCED_OPTIMIZATIONS 开启的情况下。我的意思是它已经做了许多其他更复杂的事情,这些事情可能会严重破坏我的 javascripts(有时确实如此,幸运的是我有单元测试来知道什么时候发生)。此外,当 Closure 编译器确实这样做时,我的代码中有一个案例!我会用一个例子来编辑。
  • @wvxvw 这还不错。共有三种编译模式。一个删除 WHITESPACE_ONLY(超级安全),另一个删除 SIMPLE_OPTIMIZATIONS(在 99% 的情况下应该是安全的,想想 YUI 编译器),我喜欢的一个是 ADVANCED_OPTIMIZATIONS,在换句话说,除非你非常小心,否则它很有可能会破坏你的代码,但从好的方面来说,代码运行得更快,而且比你的普通缩小器可以做的要小得多。
  • @CamiloMartin:恕我直言,我当然相信您直接比较这两种方法表明单个对象分配比空对象分配后跟多个属性分配要快,但是如果您比较给定这两种方法的库的整个加载,我很难相信差异是可察觉的。如果这是一些需要快速连续运行多次的代码,那么这些小的优化可能是值得的,但对于一次性操作,我不会花太多时间试图超越编译器。
  • 并不是我想尽量减少你的问题。但是我已经花了足够的时间尝试为 Closure Compiler 调整我的代码,以知道它几乎没有产生任何真正的区别。
  • @user1689607 嗯,你的观点是有道理的,我想这有点固执。如果我找不到方法,我会放弃它,只做属性分配。

标签: javascript properties google-closure-compiler object-literal minify


【解决方案1】:

我正在做一个解决方法。它可能不适用,因此无法接受此答案。不过,这对我来说是有效的。

我的文件夹结构如下所示:

src
├───components
└───core

而且,在编译之前,我合并了src/intro.jssrc 级别的一些文件(按特定顺序),然​​后是core 中的所有文件(任何顺序),然​​后是components 中的所有文件(任何顺序),然​​后是outro.js

现在,文件夹结构如下所示:

src
├───components
│   ├───modules
│   └───plugs-literal
└───core
    ├───internal
    ├───modules
    └───plugs-literal

并且编译顺序是(注意带箭头的部分):

  • src/intro.js
  • src/core 中的几个文件,具体顺序。
  • src/core/internal 中的所有文件
  • src/core/plugs-literal-intro.js
  • src/core/plugs-literal中的所有文件
  • src/components/plugs-literal 中的所有文件
  • src/core/plugs-literal-outro.js
  • src/core/modules 中的所有文件
  • src/components/modules 中的所有文件
  • src/outro.js

这个想法是一个文件包含一个对象文字的开头,另一个文件包含一个对象文字的结尾,两个文件夹包含属性。或多或少是这样的:

src/core/plugs-literal-intro.js:

var myObjectLiteral = {
    'someSimpleProp': 'foo',
    'someOtherSimpleProp': 'bar',
    'lastOneWithoutTrailingComma': 'baz'

src/core/plugs-literal/EXAMPLE.js:

,'example': function() { alert('example'); } // comma before, not after.

src/core/plugs-literal-outro.js:

};

如果这引入了一些不必要的问题,我稍后会知道。但是,我可以分配一个不同的文件夹来包含单独声明的原型属性。

【讨论】:

    猜你喜欢
    • 2013-09-05
    • 2011-01-13
    • 1970-01-01
    • 2018-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多