JavaScript的类型错误:Illegal invocation

今天写一个十分简单的页面,要获取页面中某一DOM,用了如下的写法:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
 <head>
  <title> new document </title>
  <meta name="generator" content="editplus" />
  <meta name="author" content="" />
  <meta name="keywords" content="" />
  <meta name="description" content="" />
  <meta http-equiv="content-type" content="text/html;charset=utf-8" />
 </head>
 
 <body>
  <div id="demo">demo</div>
    <script type='text/javascript'>
   1:  
   2:         var d = document.getElementById;
   3:  
   4:         var s = d("demo").innerHTML;
   5:         
   6:         alert(s);
   7:     
</script>
 </body>
</html>

昨一看好像也没什么问题,在IE6~8下运行也没有任何的问题,可是在其它浏览器下就报错了,报了这样一个错:

Uncaught TypeError: Illegal invocation    未捕获的类型错误:非法调用

 

当时没太注意,当时没仔细去弄清楚是怎么回事,然后在微博中发一条消息,稍作了一下记录。等吃完饭回来看到有一条回复,是taibo转播的,说明了原因:call/apply 上下文非法时,会抛出此异常,IE9也遵守此规范。后面是可以避免报此错误的一个example,我一看没太注意,之后他又发了一个ref

Calling a Method with a Function Pointer without ".call" or ".bind"

看完以后才真正缓过神来,上面的在IE9和非IE(例如Chrome)浏览器下的写法如同:

<script type='text/javascript'>
        var d = document.getElementById;
        
        var s = d.call(window, "demo").innerHTML
        
        alert(s);
    </script>

这样写显然会导致调用错误,因为id为demo的DOM元素应该是在document对象中,而不是在其它对象中。改为调用document就可以得到想要的结果:

<script type='text/javascript'>
        var d = document.getElementById;
        
        var s = d.call(document, "demo").innerHTML
        
        alert(s);
    </script>

但是在我的IE6下却报错了,然后我开始找原因了…

 

 

我试图去循环迭代出d中的所有属性

var d = document.getElementById;
        
for (var p in d){}

但得到的情况很糟糕,不知道是我的系统问题,还是确实存在这个问题,运行后直接出现了“"0x7e2cf10c" 指令引用的 "0x00000000" 内存。该内存不能为 "read"。 ”

R4ORJAQV1EO~)CGF}AT(`{E

 

之后我尝试着使用typeof,想看看它到底是个什么东东,按我的预期,它应该是一个函数,只有函数才能被调用“()”

var d = document.getElementById;
        
alert(typeof d);

在我的IE6中得到的结果让我很失望“object”,好在Chrome下得到的是 “function”。也许你觉得上面的typeof可能不准,那使用下面的方法应该是没什么异议了吧

alert(Object.prototype.toString.call(d));  结果依旧表明:ie下为object而Chrome则为function

image      image

 

最为神奇的是在我的ie6下,d是没有toString方法的,我想它应该是一个很“干净”的对象吧(没有toString、valueOf方法),而Chrome是符合预期的

image   image

 

更重要的是它不Function的实例,更不是Object的实例,而在Chrome下也符合预期。

var d = document.getElementById;
        
alert(d instanceof Function);
alert(d instanceof Object);

 

它到底如何实现的呢?如果是Global对象下的方法,如parseInt、isNaN等,它应该可以被删除,很明显的它属于docuemnt对象下的方法而不是Global下的方法。至于它到底怎么实现的,我暂时还不太清楚,只是觉得一个对象 object(要么它的typeof有问题),也可以被调用,这个就很神奇了。

 

()在javascript虽然有多义性,但无非下面几种:

1、函数声明时的函数列表 例:function fnName(arg1, arg2) {};

2、和一些语句一起使用用来限定的作用,例:for()、while()等:

3、和new一起使用,用来传递参数--在不传递参数的情况下()可以省略,但并不建议  例:var obj1 = new FunName();

4、计算一个表达式,提升运算的优先级 例:var  a = 5 * (3 + 4)

5、正则表达中用作捕获的分组之用

6、函数调用符

 

上面的问题让我困惑的是,一个object如何被调用,这里的()肯定是函数调用符,那么document.getElementById应该是一个函数才对,而实际得到的结果却不是(还是这个测试类型得到的结果有问题?!)

 

需要说明一下情况的是,最初写的页面不是在宿舍写的,用的浏览器是IE8,而我回宿舍之后本本上装的是IE6(为了测试之用,虽然我很痛恨ie6),其它浏览器暂时没全部测试过。

posted @ 2011-04-24 23:42  meteoric_cry  阅读(63337)  评论(1编辑  收藏  举报