首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >闭包编译器ADVANCED_OPTIMIZATIONS和函数封装

闭包编译器ADVANCED_OPTIMIZATIONS和函数封装
EN

Stack Overflow用户
提问于 2011-06-09 05:35:21
回答 1查看 681关注 0票数 2

使用谷歌闭包编译器(ADVANCED_OPTIMIZATIONS),似乎当代码封装在一个函数中时,有一些高级优化无法完成。

代码语言:javascript
复制
(function(){
var db = {};
/** @enum {number} */
db.col = { One: 0, Two: 3, Three: 4, Four: 1, Five: 2, Six: 7, Seven: 8 };
alert(db.col.Two); alert(db.col.Three); alert(db.col.Four);
})();

var db = {};
/** @enum {number} */
db.col = { One: 0, Two: 3, Three: 4, Four: 1, Five: 2, Six: 7, Seven: 8 };
alert(db.col.Two); alert(db.col.Three); alert(db.col.Four);

编译为

代码语言:javascript
复制
var a={a:{f:0,d:3,c:4,b:1,e:2,h:7,g:8}};alert(a.a.d);alert(a.a.c);alert(a.a.b);
alert(3);alert(4);alert(1);

函数封装阻止高级变量替换的原因是什么?有没有办法让这两个片段编译成相同的输出呢?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2011-06-09 12:11:55

一种可能的解释是:

您所指的闭包编译器的特性是“名称空间扁平化”,这是编译器试图规避与在名称空间的长链中查找相关的开销。

例如,foo.bar.baz.hello.doSomething();需要导航一个由四个对象组成的链来查找doSomething属性。通过名称空间扁平化,该属性将扁平化为a,并由a();替换调用--这是一个显著的改进。

因此,在第二种情况下,真正有问题的并不是对象db。我相信下面的优化链会发生:

代码语言:javascript
复制
var db = {};
db.col = { One: 0, Two: 3, Three: 4, Four: 1, Five: 2, Six: 7, Seven: 8 };
alert(db.col.Two); alert(db.col.Three); alert(db.col.Four);

名称空间扁平化:

代码语言:javascript
复制
var a=0, b=3, c=4, d=1, e=2, f=7, g=8;
alert(b); alert(c); alert(d);

然后,因为b、c、d都只使用一次,所以它们是内联的:

代码语言:javascript
复制
var a=0, e=2, f=7, g=8;
alert(3);alert(4);alert(1);

最后,丢弃未使用的变量a,e,f,g。

然而,尽管这在全局作用域中工作得很好,但当在闭包中定义对象时,编译器必须格外小心,因为在该闭包中可能会有函数调用来捕获在该闭包中定义的对象。闭包中的所有东西都必须是“无副作用的”,以便编译器“扁平化”对象并消除对象;否则,如果内部函数调用引用的捕获对象不再存在,代码将中断。

alert()并不是假定没有副作用。因此,假设可以通过调用alert来修改dbdb.col。之后任何可能没有副作用的代码都可以引用修改后的dbdb.col,因此不能删除这些对象。注意:如果alert()调用是最后一个无副作用的调用,则不适用。

要启用名称空间扁平化,您必须将对象移动到闭包之外,并在全局范围内定义它们,这是无法捕获的:

使用对象表示法将对象定义移到函数闭包之外(因此使它们使用namespaces)

  • Avoid

这将会起作用:

代码语言:javascript
复制
var db = {};    // Put the namespace outside, making it global
db.col = {};    // Put sub-namespaces outside also

(function(){
    db.col.One = 0;    // Avoid using object notation
    db.col.Two = 3;
    db.col.Three = 4;
    db.col.Four = 1;
    db.col.Five = 2;
    db.col.Siz = 7;
    db.col.Seven = 8;

    alert(db.col.Two); alert(db.col.Three); alert(db.col.Four);
})();

一个很好的实验是:

代码语言:javascript
复制
(function() {
    var db = {};
    db.col = { One: 0, Two: 3, Three: 4, Four: 1, Five: 2, Six: 7, Seven: 8 };
    alert(db.col.Two);   // Only one call
    var test = db.col.Three + db.col.Four;   // This statement is side-effect-free
})();

瞧啊!它是有效的:

代码语言:javascript
复制
alert(3);

但是:

代码语言:javascript
复制
(function() {
    var db = {};
    db.col = { One: 0, Two: 3, Three: 4, Four: 1, Five: 2, Six: 7, Seven: 8 };
    alert(db.col.Two);     // First call, anything afterwards is suspect
    alert(db.col.Three);   // Oops!  Cannot eliminate db or db.col!
})();

不工作吗?

代码语言:javascript
复制
var a={a:{f:0,c:3,b:4,e:1,d:2,h:7,g:8}};alert(a.a.c);alert(a.a.b);
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6285567

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档