为什么一些浏览器本地全局对象被写为window.object而其他对象只是作为对象?

时间:2013-05-01 22:20:46

标签: javascript google-closure-compiler

某些浏览器本地全局对象是使用window编写的,而其他对象则是。

window.setTimeout
window.getComputedStyle
JSON
decodeURIComponent

为什么呢?有什么不同?这会为所有情况返回true

'setTimeout' in window
'getComputedStyle' in window
'JSON' in window
'decodeURIComponent' in window

我首先注意到使用Closure Compiler时存在明显差异。

输入

// ==ClosureCompiler==
// @compilation_level ADVANCED_OPTIMIZATIONS
// @output_file_name default.js
// @formatting pretty_print
// ==/ClosureCompiler==

window.decodeURIComponent;
window.getComputedStyle;
window.setTimeout;
window.JSON;
decodeURIComponent;

输出

window.a;
window.getComputedStyle;
window.setTimeout;
window.JSON;
decodeURIComponent;

它有decodeURIComponent defined as an extern,但在与window一起使用时仍会重命名。

2 个答案:

答案 0 :(得分:1)

对此没有一个好的答案。

正如您所观察到的,在Closure-compiler默认externs中,一些对象被定义为窗口对象上的属性,一些被定义为全局对象,一些被定义为两者。确实没有充分的理由 - 只是外围人员就是这样开发的。默认的externs会随着时间的推移而发展,因此在开发人员需要时会添加定义,这些定义会开始解释当前的状态。

高度需要的任务是从已发布的IDL文档生成外部的方法。但是,这种更改可能会破坏现有代码(默认类型名称可能会略有变化),到目前为止还没有开发人员愿意承担这项任务。

更新注意:并不是真的希望将所有全局变量定义为window上的对象和属性。这样的代码只会弹出默认外部的大小。但是,应该在两者上定义常用的外部。

鼓励开发人员使用VERBOSE警告,以便编译器警告未定义的属性。

答案 1 :(得分:0)

没有区别。您需要了解的是JavaScript全局范围。

每当我尝试解析变量名称时,无论是什么,都会查找范围链。

想象一下你有这个:

function() {
    var k = 5;
    function() {
        (function() {
           k = 6;
        })();
    };
};
console.log(k);

正如您所看到的,放置它的位置并不重要,更高的订单定义是“记住的”,除非您手动覆盖它。

setTimeout也是如此。无论您将setTimeout放置在代码中的哪个位置,无论您嵌套多少次,JavaScript都会查找它并在window中找到它,它会解析它。

无论您键入window.something还是something都没有区别,因为如果存在某些内容将在全局范围内解析,或者如果找不到则会抛出ReferenceError

Closure Compiler (以上与编译器的行为无关)。

Closure Compiler以这种方式是愚蠢的,至少从浅的角度来看。告诉它“不要碰这个属性”是不好的方法。

阻止属性重命名的简单方法是通过["property"]访问它。请允许我演示:

var a = {};
a["bla"] = "bla";// compiler will not touch this.
a.bla2 = "bla2"l;// compiler will flatten this!!

但您必须记住始终通过a["property"] 访问该属性,否则您对a.property的调用将被重新写入a.ab或其他任何内容。失败!!

所以现在你需要window["decodeUriComponent"],一切都会好的。虽然很奇怪,但它是最简单的技巧。编译器会将上述内容转换为window.decodeUriComponent,但不会触及实际名称。