Closure Compiler并不总是内联枚举。为什么?

时间:2014-07-13 13:41:45

标签: javascript enums google-closure-compiler

Google的Closure Compiler遵循哪些规则来决定enum是否内联?

当我通过Closure Compiler运行代码时,JSDoc annotation enum类型未内联。然而,当我创建一个简化的示例时,enum类型被内联,因为这个无意义的示例将演示:

 var my_name_space = (function () {
     'use strict';

     /** @enum {number} */
     var TASK_STATUS = {
         REJECT: -1,
         UNKNOWN: 0,
         APPROVE: 1
     };

     function init_(a) {
         if (a === TASK_STATUS.UNKNOWN) {
             alert("Reject");
             a = TASK_STATUS.REJECT;
         } else if (a === TASK_STATUS.APPROVE) {
             alert("Unknown");
             a = TASK_STATUS.UNKNOWN;
         } else {
             alert("Approve");
             a = TASK_STATUS.APPROVE;
         }
         return a;
     }
     return { init: init_};

 }());  // my_name_space


 my_name_space.init(-1);

Closure的输出:

 var my_name_space=function(){return{init:function(a){0===a?(alert("Reject"),a=-1):1===a?(alert("Unknown"),a=0):(alert("Approve"),a=1);return a}}}();my_name_space.init(-1);

事实上,无论有没有JSDoc标题,都会出现衬里。

请解释衬里在什么条件下不会发生,或者甚至更好,请修改以上内容,以证明衬里不会发生。

我正在使用'简单'优化级别。

2 个答案:

答案 0 :(得分:3)

首先,枚举不是用于优化目的的特殊对象,但是,@enum对于类型检查很有用,并且具有用于此目的的特殊规则。

至于内联,有很多东西可以阻止内联,展示所有可能性是不合理的,但我可以告诉你为什么它们可能不是:

  • 枚举对象被定义为对象上无法分解为变量的属性(ADVANCED模式对此有帮助)
  • 枚举是在全局变量上定义的(ADVANCED模式有帮助)
  • 枚举对象的别名方式是别名本身无法删除(将枚举对象传递给无法内联的函数,将枚举对象分配给全局值)。
  • 迭代枚举键/值(for-in等)
  • enum对象被覆盖

这些都归结为编译器无法确定它可以:

  • 删除对象并将其替换为单个值
  • 内联这些值

也就是说,如果你有一个简单的局部定义,并且你只引用了值而不是对象本身,并且值本身是简单的常量(数字,布尔值),它总是会被内联。

答案 1 :(得分:1)

首先,我相信你必须使用ADVANCED_OPTIMIZATIONS从内联获得任何胜利。您当前的代码目前对ADVANCED OPTIMIZATIONS无效,因此我进行了修改以使其正常工作。

 /** @enum {number} @const */
 var TASK_STATUS = {
     REJECT: -1,
     UNKNOWN: 0,
     APPROVE: 1
 };

 /**
  *  @param {TASK_STATUS} a
  */
 function init_(a) {
     if (a === TASK_STATUS.UNKNOWN) {
         alert("Reject");
     } else if (a === TASK_STATUS.APPROVE) {
         alert("Unknown");
     } else {
         alert("Approve");
     }
 }

init_(TASK_STATUS.REJECT);

输出:

alert("Approve");

闭包编译器无法内联代码的原因有几个原因。 Closure编译器不会一直深入到您的代码中 - 它通常使用您传入的类型信息来做出决策。通过对象表达式传递函数效果不佳。 (即,通过对象文字传递init函数)

其次,你的init函数有副作用(分配a)。由于闭包编译器不知道什么是真正被更改的(没有类型信息),所以它做了安全的事情,并没有内联函数。

高级模式下的Closure编译器是一个野兽。这需要一些时间来适应。