zoukankan      html  css  js  c++  java
  • Javascript之旅——第八站:说说instanceof踩了一个坑

     

    前些天写js遇到了一个instanceof的坑,我们的页面中有一个iframe,我在index页面中计算得到了一个array,然后需要传递到Flight页面这个嵌套的iframe中的一个函数(SearchFlight)中,作为防御性编程,我需要在SearchFlight函数中进行参数检测,也就是判断过来的参数一定是Array类型。

    一:抛出问题

    举个例子,下面有两个页面。

    Index.html页面

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title></title>
    </head>
    <body>
     
        <iframe name="childframe" src="Flight.html"></iframe>
     
        <script type="text/javascript">
     
            window.onload = function () {
                //航班
                var airplanes = ["MU", "CA", "CZ"];
     
                var result = window.frames[0].flight.SearchFlight(airplanes);
            };
        </script>
    </body>
    </html>

    Flight.html页面

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title></title>
    </head>
    <body>
        <script type="text/javascript">
     
            var flight = (function () {
     
                return {
                    SearchFlight: function (arr) {
                        var result = arr instanceof Array;
                        alert(result);
                    }
                };
            })();
        </script>
    </body>
    </html>

    很惊讶的发现instanceof居然不能判断出arr是一个数组,其实我们用肉眼可以看到,压根它就是一个数组,但是为什么instanceof却判断不出来呢?

    我们知道instancof其实是一个js语法糖,我就修改成简单点的,判断arr.constructor是否指向Array,于是我把关键字改成如下形式,再来看看看效果。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var flight = (function () {
     
                return {
                    SearchFlight: function (arr) {
                        //var result = arr instanceof Array;
     
                        var result = arr.constructor == Array;
     
                        alert(result);
                    }
                };
            })();

    从图上看,还真有点奇怪,明明都是function Array(),为啥都不能相等呢?不过事实就摆在眼前,容不得狡辩,只能静下心来想一想,我们知道Array在js是属于引用类型,既然不相等那就说明他们其实是两个引用,对不对,并且Array是挂在window下的一个属性,window属性也就是一个窗口的实例,那就说明Index.html是一个window实例,Flight.html也是一个window实例,为了验证下,我们看看两个window是否相等?

    看完图后,答案就很明白了,以C#的思维考虑一下,既然大的window都不相等,里面的Array属性自然就不相等,终于问题是找到了,下面怎么解决呢?

    二:解决问题

    1. length判断

    这个很容易想到,也是最简单的,我们知道每个数组都有length,所以可以简简单单的看length是否存在就可以了,但是这个也不是万无一失的,我们知道function中有两个属性length和prototype,那这就有问题了。这样我会错误的把f认为是数组。

    2.使用prototype的call方法来实现

    这个方法有点巧妙,首先我们要知道,每一个function中都会有call方法和prototype属性,而js在Object.prototype中的tostring函数上做了一个封装,就是调用tostring.call后,会返回[object constructorName]的字符串格式,这里的constructorName就是call参数的函数名,比如我们把arr传进去,就会返回“[object Array]”字符串格式,这个方法也可以让我们巧妙的判断是否是Array,但是比较遗憾的是,我们看不到这个call的内部实现,只能黑盒的记住了。


    原文出处: 一线码农的博客   欢迎分享原创到伯乐头条

  • 相关阅读:
    Vue-router的实现原理
    get请求被浏览器跨域的同源策略请求机制拦截,但是get请求是否请求到了服务器呢
    合并两个有序链表
    JS实现链式调用 a().b().c()
    CSS知识点总结
    BK-信息查找、摘取
    radar图生成用户guideline
    【转】 mybatis 详解(七)------一对一、一对多、多对多
    【转】 mybatis 详解(六)------通过mapper接口加载映射文件
    【转】 mybatis 详解(五)------动态SQL
  • 原文地址:https://www.cnblogs.com/sunscheung/p/4342099.html
Copyright © 2011-2022 走看看