• 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),其它浏览器暂时没全部测试过。

  • 相关阅读:
    国内最火的3款前端开发框架
    Cordova是做什么的
    老师你好。使用cordova生成的hellowold 的安卓5.0版本太高。怎么才可以生成4.4的呢?
    一个类似bootstrap的foundation
    role在标签中的作用是什么?
    如何做到根据不同的进度用不同的颜色显示整个进度条
    wall 和panel有啥区别
    git ignore
    eclipse js 引用跳转
    计划
  • 原文地址:https://www.cnblogs.com/meteoric_cry/p/2026582.html
Copyright © 2020-2023  润新知