打印

BX9045: 各浏览器中 window 对象的构造器不同

作者:钱宝坤

标准参考

window 对象本身属于 BOM ( Browser Object Model ) 范畴,W3C 现行 HTML 与 DOM 相关规范中并没有制定他,因此 BOM 具体实现由各浏览器厂商分别制定。

在现有最新的 HTML5 规范草案中,window 对象的接口名为 Window,其详细内容可参照: 5.2 The Window object

问题描述

原本属于 BOM 范畴的 window 对象,其构造方法在各浏览器中实现不同:

  • IE6 IE7 IE8(Q) 中,,window 对象的构造器不可被探知;
  • IE8(S) Firefox 中,window 对象的构造器 Window 可以被直接在代码中调用 (他们构造器的名字与 HTML5 规范草案中规定的“恰巧”相同);
  • Chrome Safari 中, window 对象的构造器 DOMWindow 不能直接硬编码使用,但可以通过 window.constructor 语句访问到;
  • Opera 中,window 对象的构造器是 Javascript 原生 Object 对象。

造成的影响

对于如此混乱的 window 构造器,草率使用将会导致各个浏览器中脚本执行出错,或者无意间污染 Javascript 的所有原生对象。

受影响的浏览器

所有浏览器

问题分析

1、window 对象的构造器探查

由于各浏览器实现 BOM 的随意性,我们首先需要探知各浏览器中 window 对象的构造器都是什么。

以下代码通过调用 window 对象的 constructor 属性得到他的构造器:

window.onload = function (){
  var msg = document.createElement("h2");
  try{
    msg.innerHTML = "window 对象的构造器为 : " + window.constructor.toString();
  }catch(e){
    msg[0].innerHTML = "window 对象的构造器不可探知";
  }
  document.body.appendChild(msg);
}

各浏览器中运行结果为:

  window 构造器
IE6 IE7 IE8(Q) 不可探知
IE8(Q) Firefox Window
Chrome Safari DOMWindow
Opera Object1

在 Opera 浏览器中使用 Object === window.constructor 语句探知两者关系将返回 true ,说明构造器就是 Object 对象。

2、window 对象的构造器使用

在除去 IE6 IE7 IE8(Q) 的浏览器中输入相应构造器名称的硬编码直接调用,结果如下:

IE8(Q) Firefox Window 可直接使用
Chrome Safari ReferenceError: DOMWindow is not defined
Opera Object 可直接使用

可见,Chrome Safari 中的 DOMWindow 构造器不可通过硬编码直接访问。

将调用方式改变,使用 window.constructor 语句来引用 window 的构造器,各浏览器运行结果如下:

IE8(Q) Firefox Window 可使用
Chrome Safari DOMWindow 可使用
Opera Object 可使用

此部分内容说明,Chrome Safari 中 window 对象构造器,不能使用硬编码方式直接访问,只能通过调用 window.constructor 语句 "迂回" 得到其引用。

3、window 对象的构造器方法扩充

得到构造器引用后可以通过 prototype 特性扩展其后代的公用方法或属性,分析以下代码:

window.onload = function (){
    var msg;
    msg = document.createElement('h2');
    msg.innerHTML = '扩充 window 对象构造器方法,其他 Javascript 原生对象是否可访问:'
    document.body.appendChild(msg);
    var objectList = {
            'window':window,
            'String':String,
            'Number':Number,
            'Function':Function,
            'Boolean':Boolean,
            'Array':Array,
            'Math':Math,
            'Date':Date,
            'RegExp':RegExp,
            'Object':Object
            };
    try{
        window.constructor.prototype.myTest = function (){};
    }catch(e){
        msg = document.createElement('h2');
        msg.innerHTML = 'window 对象的构造器不可扩充';
        document.body.appendChild(msg);
        return;
    }
    for (var i in objectList){
        msg = document.createElement('h2');
        msg.innerHTML =  i + '对象 : '
            + (
                objectList[i].myTest
                ?' myTest 方法存在'
                :' myTest 方法不存在'
            );
        document.body.appendChild(msg);
    }
}

代码中通过 prototype 特性为 window 的构造器扩展了个名为 myTest 的方法,然后依次遍历 window、String、Number、Function、Boolean、Array、Math、Date、RegExp、Object 对象,并试图访问 myTest 方法。各浏览器运行结果如下:

IE6 IE7 IE8(Q) window 对象的构造器不可扩充
IE8(Q) Firefox window 对象可访问其构造器扩充的方法
Chrome Safari window 对象可访问其构造器扩充的方法
Opera 所有 Javascript 对象均可访问其构造器扩充的方法

表中情况说明:

  • IE6 IE7 IE8(Q) 中 window 对象的构造器不可扩充;
  • IE8(Q) Firefox Chrome Safari 中, window 对象的构造器扩充后的方法只有 window 对象可以访问;
  • Opera 中 window 对象构造器是 Object ,因此对其扩展私有方法既是对 Object 对象的扩展,这会造成 JavaScript 全部原生对象被污染
    同样,也是由于构造器是 Object 缘故,Opera 中可以使用 new window.constructor 语句,这将创建一个 Object 对象而不是 window 对象。在其他浏览器中执行 new window.constructor 试图创建新的 window 对象将会报错。

解决方案

window 对象的构造器在个浏览器内支持非常混乱,因此强烈不建议在实际应用中使用

参见

知识库

相关问题

测试环境

操作系统版本: Windows 7 Ultimate build 7600
浏览器版本: IE6
IE7
IE8
Firefox 3.6.8
Chrome 7.0.517.0 dev
Safari 5.0.1
Opera 10.62
测试页面: window_constructor.html
本文更新时间: 2010-09-25

关键字

window Window DOMWindow instanceof constructor BOM HTML5 规范草案 构造器