在Firefox中,open()和window.open()有什么区别?

6

在回答我的问题时,Pumbaa80发现调用open()window.open()之间存在差异,请尝试以下示例 在Firefox中进行测试(在11.0上测试):

  1. http://jsfiddle.net/9kqp5/(调用open在 FF 中在新标签页中打开,默认情况下会打开“在新标签页中打开新窗口”设置)

  2. http://jsfiddle.net/HLbLu/(调用window.open;在新的小窗口中打开

但是,到底为什么会有差异呢?如果我尝试以下示例

<script>
var a = 2;
function hello() { alert(this.a); }

hello();
window.hello();
</script>

使用两种不同的方法调用函数 hello,它们工作方式完全相同,包括有相同的 this !!!


1
对我来说都一样,你的所有示例打开的是同一件事。实际上它们是相同的,除非你定义另一个函数调用“open”。 - Eric Yin
两个JS Fiddles对我来说都表现出相同的行为(打开一个新窗口)。 - David Thomas
我也是,尝试了Opera和Firefox。 - Imp
我的Firefox(3.6.21)表现如预期(window.openopen相同),并且这两个Fiddles都会打开一个新窗口。但是,我认为后续版本可能会微妙地更改定义以适应选项卡。 - Andrew Leach
对不起大家!我想提到Firefox中的一个区别,但不小心删掉了,它只存在于关键字中。现在已经添加回来了!Firefox中的差异在链接问题中有更详细的描述。 - Tomas
我稍微更新了一下我的问题。条件是,“在新标签页中打开新窗口”选项已经开启,默认情况下是这样的。 - Tomas
6个回答

7

错误报告的要点是,目前在您的情况下document.openwindow.open具有不同的行为:前者打开一个新标签页,而后者打开一个小的新窗口。它们应该具有相同的行为,并且该行为应该是打开一个小的新窗口。这就是我编写的补丁所做的;您应该查看补丁,特别是其中的测试。 - Boris Zbarsky
Boris,我担心的趋势是禁用打开新窗口..而调用window.open是最后的机会。我担心他们会以另一种方式解决这个问题:window.open将像document.open一样行事,即两者都将进入新标签页(前提是您已在FF属性中设置“在新标签页中打开新窗口”,这是默认设置)。 - Tomas
接受Boris的答案作为关键和最完整的答案,然而第一段更清晰明了来自Cheran的回答。 - Tomas
根据whatwg链接和注意到的行为,这并不是一个bug... document.open只是一个负载过重的函数,需要前3个参数像window.open一样运作。(除非我完全读错了。) - user166390
你读错了。带有三个参数的 document.open 只是尾调用到 window.open - Boris Zbarsky
显示剩余3条评论

6
在事件处理程序内部,仅使用open会解析为document.open。正如Boris Zbarsky在评论和他的回答中提到的那样,这是HTML5指定的预期行为。在事件处理程序部分,第6步规定如下:

6.使用上面创建的脚本执行环境,创建一个函数对象(在ECMAScript第5版第13.2节中定义的函数对象),具有:

(...)
词法环境范围(Lexical Environment Scope)

  1. 让Scope成为NewObjectEnvironment(元素的文档,全局环境)的结果。
  2. 如果元素具有表单所有者,请让Scope成为NewObjectEnvironment(元素的表单所有者,Scope)的结果。
  3. 让Scope成为NewObjectEnvironment(元素的对象,Scope)的结果。
    (...)
换句话说,在事件处理程序内部,变量引用将按以下顺序解析:
  1. 本地作用域(local scope)
  2. 元素属性(element properties)
  3. 所有者表单属性(如果适用)(owner form properties (if applicable))
  4. document属性(document properties)
  5. 全局作用域(global scope)

啊哈,干得好!不过这个行为非常奇怪。就像处理程序被嵌套在with块中一样。我从来没有想到过。 - user123444555621
@Pumbaa80 嵌套块正是这种行为的本质。没错,它很荒谬,但在浏览器中已经存在了很长一段时间,而且很多网站不幸地依赖它。 - Boris Zbarsky

4

在Chrome浏览器上,您的两个小提琴对我来说效果相同。

然而,以下两行代码:

window.open(...);

open(...);

是不等效的。它们只有在当前执行范围未为open提供新定义时才会等效,从而使解释器查找更高的范围,直到达到全局范围并找到window.open

您可以在此小提琴中看到其效果:

var test = function () {
    var open = function () {
      alert('uh oh');  
    };

    window.open('www.google.com');
    open('www.google.com');
};

test();

是的,这很明显,但是如果你看一下我问题中的两个fiddle,它们都在全局上下文中调用了open,但仍然存在差异! - Tomas
@Tomas 我认为你需要指定你正在使用的Firefox版本。到目前为止,没有人复制这种现象。 - Andrew Leach
@AndrewLeach,当然是最新的版本了...(这是默认值 :-)). 版本11.0。 - Tomas

1
它们实际上是相同的。尝试使用window.open === openwindow["open"] === open。如果这对你来说是错误的,那么你必须处于闭包中,并且某些代码已经定义了open。
当然,这适用于所有作为全局(window)对象成员的对象。

1

这确实非常奇怪。看起来,onclick 处理程序 当作为属性添加时,与包装的 open 函数有一些上下文不同,与 window.open 不同:

http://jsfiddle.net/aFujb/

这在最新的Firefox、Safari和Chrome中发生。我找不到任何关于这两个浏览器的解释或错误报告。

我试图在Firefox的源代码中找出发生了什么,但老实说,对我来说太多了。看起来有两种不同的window.open实现,分别称为nsGlobalWindow::OpennsGlobalWindow::OpenJS,但我不确定这是否与问题有关。


终于有人了!感谢你的调查,Pumbaa。 - Tomas
1
这不是一个 bug。在你的 fiddle 中,open 的裸字查找发生在 onclick 属性中,因此它首先在该属性所在的元素上进行查找,然后在文档上进行查找,最后在窗口上进行查找。当然,在它到达窗口之前,它会先找到 document.open... - Boris Zbarsky
@BorisZbarsky是正确的;请参见我的答案以了解原因。 - Cheran Shunmugavel

0
在浏览器中,默认上下文是window。这就是为什么你可以调用open()alert()甚至escape()等函数。调用window.open()与调用open()完全等效。
通过open()函数调用打开新窗口的方式完全取决于您使用的浏览器。

但是你如何解释这两个小提琴之间的区别呢? - Tomas
没有区别。如果将新窗口设置为在浏览器中打开标签页,则它们将作为标签页打开。如果取消该设置,则它们将作为新窗口打开。您需要指定在哪个浏览器和版本中看到了差异以及您的新窗口策略是什么。确保没有运行可能影响新窗口/标签式浏览的特殊插件。 - Eli Sand
Pumba 在这里观察到了相同的差异... 我没有任何特殊的选项卡插件,只使用了FF 11.0与Firebug、Web开发工具栏和RealPlayer浏览器记录附加组件。请参见我在问题中更新的设置说明。 - Tomas
不知道该告诉你什么 - 这里的每个人都在说同样的话; 他们无法重现你所经历的问题。除非有人查看你从Firefox的about:config获得的完整输出,否则我会认为这要么是你不知道的插件,要么是你Firefox配置文件中的残留设置(你升级到11了吗,还是使用新配置文件?)。 - Eli Sand

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