全局JSON变量覆盖

4
我在项目中使用了json2.js,因为浏览器(IE8)不支持将字符串解析为JSON对象。
我查看了json2.js,并对变量声明产生了疑问。 json2.js中声明了一个全局的JSON变量。
var JSON;
if(!JSON){
    JSON={};
}

声明var JSON;对全局JSON对象有什么影响? 我希望这个声明可以在任何浏览器(IE8/IE7)中覆盖全局JSON对象。 但令我惊讶的是,当存在全局对象时,它并没有被覆盖。 只有变量定义/初始化才会覆盖全局变量? 请澄清。

当IE 8设置为“标准模式”时,它具有JSON支持。 - Joseph
但是我的内部网页(使用JSF和Richfaces)始终以IE7模式加载。这是另一回事。 - Ahamed Mustafa M
4个回答

3

var关键字可以确保在封闭函数中或者(像这里一样)在window中存在变量,但是它不会初始化变量。

实际上,顺序并没有真正的影响。

以这段代码为例:

a = 3;
var a;
alert(a);

它会提示“3”。

因此,代码中的var声明仅确保测试中不会出现错误,并且不会删除现有值。

牢记这一点很重要,因为javascript中常见的一个错误是在函数中有多个var声明,并对甚至在var声明之前设置的值感到惊讶。例如,运行以下代码:

if (true) {
    ​a = 3;
}
// lot of code, at a different level
if (true) {
    var a;
    if (433/43==3) a=true;
    if (a) alert('should not happen');
};
​

是的,变量是附加在函数而不是块级作用域上的...

这里有点不同。在你的例子中,变量声明被提升到了顶部。所以即使你像这样写,实际执行顺序是var a; a = 3;(或者可能是var a; a = 3; var a;(未提升)这也是有道理的,然后它就会适合)。在这种情况下,JSON是环境中预定义的符号,它在变量声明被评估之前已经有一个值(我猜测)。我不知道,我只是想指出这种差异。 - Felix Kling

3
对于每个变量声明(不是初始化!),以下操作将发生(部分 #10.5):
8. 对于源代码中的每个VariableDeclarationVariableDeclarationNoIn d,按顺序执行以下操作:
- 令d中的Identifierdn。 - 调用env的HasBinding具体方法,并将dn作为参数传递,将结果赋值给varAlreadyDeclared。 - 如果varAlreadyDeclaredfalse,则:
- 调用env的CreateMutableBinding具体方法,将dnconfigurableBindings作为参数传递。 - 调用env的SetMutableBinding具体方法,将dnundefinedstrict作为参数传递。
所以你可以看到,每当遇到var x时,就会检测环境中是否已经存在一个名为x的变量。如果是,则被忽略,但如果没有,则声明该变量并用undefined进行初始化。
由于代码是在全局作用域中运行,因此它会测试全局作用域中是否存在JSON。因此,如果JSON已经存在,则var JSON;会被忽略。

关于测试/解释这种行为的一些想法:

我不知道在JavaScript执行过程中全局对象是在哪个时刻创建的,但我假设在所有其他脚本被评估之前。这意味着,在任何变量声明之前,JSON 存在并具有一个值,在您包含两个脚本(也可以是内联的,它们会按顺序评估)时,您只能模拟这种情况。

尝试:

// script1.js
var foo = 'bar';

// script2.js
var foo;
if(!foo) {
    foo = 'baz';
}
alert(foo);

// include script2.js after script1.js

结果是什么?(作弊者请看这里)。


无论何时您在一个单独的脚本文件中,所有变量声明都会被提升到顶部。所以如果您有:
var foo = 'bar';
var foo;
if(!foo) {
    foo = 'baz';
}

脚本实际上是以以下方式执行的:

var foo;
var foo;
foo = 'bar';
if(!foo) {
    foo = 'baz';
}

你实际上无法测试第二个var foo;是否覆盖了第一个,因为此时它还没有值。因此,这不是一个很好的示例来展示上述行为。

0

这可能不是你的选择,但也可以将IE8设置为兼容模式以获取原生的JSON对象:

// in your preinit page event
Response.AddHeader("X-UA-Compatible", "IE=8");

另一个选择是仅在JSON变量不存在时创建它:
var JSON = JSON || {};

-1

如果您在执行该代码块时处于全局范围,则 var JSON 将覆盖全局 JSON 对象为 undefined。

如果您在任何其他作用域中(比如函数内部),则不会产生任何影响。


通常脚本会在全局范围内执行。那么它为什么存在呢? - Felix Kling
我的意思是:它在全局范围内执行,如果全局JSON对象已经存在,它不会覆盖它。为什么要这样做呢?那将是完全浪费。 - Felix Kling

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接