代码之家  ›  专栏  ›  技术社区  ›  danieltalsky

这是一个不错的JavaScript反射实现示例吗?

  •  1
  • danieltalsky  · 技术社区  · 15 年前

    这是一次求职面试,如果有人能关注这件事并说我有什么大错误的话,我会很高兴的。问题是:

    1)假设我们正在开发基于JS的 调试器,类似于Firebug,我们 需要一种方法来检查JS对象和 元素。写一个路由 作为输入和列表的对象/元素 输出其属性(例如 属性、方法等)、值和 数据类型。

    以下是我的实现:

    var printObjectReflection = function(showPrototypeChainProperties){
    
        // Default: false
        showPrototypeChainProperties = 
            typeof(showPrototypeChainProperties) != 'undefined' ? showPrototypeChainProperties : false;
    
        var objToReflect = this;
    
        // Create and populate collections for different lists
        var methodPropertyList = Array();
        var arrayPropertyList = Array();
        var objectPropertyList = Array();
        var scalarPropertyList = Array();   
    
        for (property in objToReflect) {
    
            var propertyName = property;
            var propertyValue = objToReflect[property];
            var propertyType = typeof(objToReflect[property]);
            // For telling integer indexed arrays from other types of objects
            var isArray = objToReflect[property] instanceof Array;
    
            // Makes sure this is an actual property of the object and not something
            // from the prototype chain, unless show is specified
            if (objToReflect.hasOwnProperty(property) || showPrototypeChainProperties){
    
                //
                // Routing to populate lists:
                //
    
                // Methods
                if (propertyType === 'function') {
                    methodPropertyList.push({"propertyName" : propertyName})
    
                // Arrays and other objects 
                } else if (propertyType === 'object') {         
                    if (isArray) {
                        arrayPropertyList.push({"propertyName" : propertyName})     
                    } else {
                        objectPropertyList.push({"propertyName" : propertyName})
                    }
    
                // Scalar member variables
                } else {
    
                    scalarPropertyList.push({
                        "propertyName" : propertyName,
                        "propertyValue" : propertyValue,
                        "propertyType" : propertyType
                    })
    
                }
            }
    
        }
    
        //
        // Cheap and dirty display
        // In real life, this would populate some kind of console or log
        // instead of simple document.write's
        //
    
        document.write('<h3>Methods in this object:</h3>');
        if (methodPropertyList.length > 0) {
            var i;
            for (i = 0; i < methodPropertyList.length; i += 1) {
                document.writeln("<strong>Method name:</strong> " +
                                 methodPropertyList[i].propertyName + "<br />");
            }   
        } else {
            document.writeln("No methods. <br /><br />");   
        }
    
        document.write('<h3>Arrays in this object:</h3>');
        if (arrayPropertyList.length > 0) {
            var i;
            for (i = 0; i < arrayPropertyList.length; i += 1) {
                document.writeln("<strong>Array name:</strong> " +
                                 arrayPropertyList[i].propertyName + 
                                 "<br />");
            }   
        } else {
            document.writeln("No arrays. <br /><br />");    
        }
    
        document.write('<h3>Non-array objects in this object:</h3>');
        if (objectPropertyList.length > 0) {
            var i;
            for (i = 0; i < objectPropertyList.length; i += 1) {
                document.writeln("<strong>Object name:</strong> " +
                                 objectPropertyList[i].propertyName + 
                                 "<br />");
            }   
        } else {
            document.writeln("No objects. <br /><br />");   
        }
    
        document.write('<h3>Scalars for this object:</h3>');
        if (scalarPropertyList.length > 0) {
            var i;
            for (i = 0; i < scalarPropertyList.length; i += 1) {
                document.writeln("<strong>Name:</strong> " +
                                 scalarPropertyList[i].propertyName + 
                                 " | <strong>Value:</strong> " +
                                 scalarPropertyList[i].propertyValue +
                                 " | <strong>Data type:</strong> " +
                                 scalarPropertyList[i].propertyType +
                                 "<br />");
            }   
        } else {
            document.writeln("No scalar variables. <br /><br />");  
        }
    
    } // end function
    

    样本使用:

    <h2>DOM Element to look for:</h2>
    <input id="inputElementToLookFor" type="text" value="monkeyShines"  />
    
    <h2>A created object literal:</h2>
    <script type="application/javascript">
    // An object we created
    var testObj = {
        'first-name' : "dan",
        'aNumber' : 234,
        'anArray' : [1,2,3,4],
        'anObject' : {"one":1, "two":2},
        'aMethod' : function() {}
    };
    
    testObj.printObjectReflection = printObjectReflection;
    testObj.printObjectReflection();
    </script>
    
    <h2>An HTML element we pulled from the DOM: </h2>
    <script>
    // An HTML element
    var myInputElement = document.getElementById("inputElementToLookFor")
    myInputElement.printObjectReflection = printObjectReflection;
    myInputElement.printObjectReflection(true);
    </script>
    

    任何人都能发现的愚蠢的错误?提前感谢您的眼球。

    编辑: 好的,这是我修订的实施。我最终完全取消了hasownpropy检查,因为它似乎让IE非常窒息,而且它不是基于hasownpropy的限制要求的一部分:

    var printObjectReflection = function(objToReflect){ 
    
        // Create and populate collections for different lists
        var methodPropertyList = [];
        var arrayPropertyList = [];
        var objectPropertyList = [];
        var scalarPropertyList = [];    
    
        for (property in objToReflect) {
    
            var propertyName = property;
            var propertyValue = objToReflect[property];
            var propertyType = typeof(objToReflect[property]);
            // For telling integer indexed arrays from other types of objects
            var isArray = objToReflect[property] instanceof Array;
    
            //
            // Routing to populate lists:
            //
    
            // Methods
            if (propertyType === 'function') {
                methodPropertyList.push({"propertyName" : propertyName})
    
            // Arrays and other objects 
            } else if (propertyType === 'object') {         
                if (isArray) {
                    arrayPropertyList.push({"propertyName" : propertyName})     
                } else {
                    objectPropertyList.push({"propertyName" : propertyName})
                }
    
            // Scalar member variables
            } else {
    
                scalarPropertyList.push({
                    "propertyName" : propertyName,
                    "propertyValue" : propertyValue,
                    "propertyType" : propertyType
                })
    
            }
        }
    
        //
        // Cheap and dirty display
        // In real life, this would populate some kind of console or log
        // instead of simple document.write's
        //
    
        document.write('<h3>Methods in this object:</h3>');
        if (methodPropertyList.length > 0) {
            var i;
            for (i = 0; i < methodPropertyList.length; i += 1) {
                document.writeln("<strong>Method name:</strong> " +
                                 methodPropertyList[i].propertyName + "<br />");
            }   
        } else {
            document.writeln("No methods. <br /><br />");   
        }
    
        document.write('<h3>Arrays in this object:</h3>');
        if (arrayPropertyList.length > 0) {
            var i;
            for (i = 0; i < arrayPropertyList.length; i += 1) {
                document.writeln("<strong>Array name:</strong> " +
                                 arrayPropertyList[i].propertyName + 
                                 "<br />");
            }   
        } else {
            document.writeln("No arrays. <br /><br />");    
        }
    
        document.write('<h3>Non-array objects in this object:</h3>');
        if (objectPropertyList.length > 0) {
            var i;
            for (i = 0; i < objectPropertyList.length; i += 1) {
                document.writeln("<strong>Object name:</strong> " +
                                 objectPropertyList[i].propertyName + 
                                 "<br />");
            }   
        } else {
            document.writeln("No objects. <br /><br />");   
        }
    
        document.write('<h3>Scalars for this object:</h3>');
        if (scalarPropertyList.length > 0) {
            var i;
            for (i = 0; i < scalarPropertyList.length; i += 1) {
                document.writeln("<strong>Name:</strong> " +
                                 scalarPropertyList[i].propertyName + 
                                 " | <strong>Value:</strong> " +
                                 scalarPropertyList[i].propertyValue +
                                 " | <strong>Data type:</strong> " +
                                 scalarPropertyList[i].propertyType +
                                 "<br />");
            }   
        } else {
            document.writeln("No scalar variables. <br /><br />");  
        }
    
    } // end function
    

    新电话:

    <h2>DOM Element to look for:</h2>
    <input id="inputElementToLookFor" type="text" value="monkeyShines"  />
    
    <h2>A created object literal:</h2>
    <script type="application/javascript">
    // An object we created
    var testObj = {
        'first-name' : "dan",
        'aNumber' : 234,
        'anArray' : [1,2,3,4],
        'anObject' : {"one":1, "two":2},
        'aMethod' : function() {}
    };
    
    printObjectReflection(testObj);
    </script>
    
    <h2>An HTML element we pulled from the DOM: </h2>
    <script>
    // An HTML element
    var myInputElement = document.getElementById("inputElementToLookFor")
    printObjectReflection(myInputElement);
    </script>
    

    谢谢大家的帮助。很遗憾,它仍然不起作用。如果我提出一个最终的实现,我会发布它。

    3 回复  |  直到 15 年前
        1
  •  1
  •   NickFitz    15 年前

    代码看起来正常。如果您真的想给他们留下深刻印象,可以考虑将结果查看器放在一起,将信息显示在列表(或表)中,并允许单击对象和数组,然后将它们显示在嵌套列表(或表)中。

    对于一个面试问题来说,这似乎是多余的,但实际上做起来相当简单,并且显示出对dom的良好理解。

    更重要的是,它提供了一些东西来提示面试官提出进一步的问题。记住:他们只有一定的时间,这会使他们的问题集中在一段你完全理解的代码上,减少他们用一个你不太了解的问题来打中你的风险。

    你越能让他们花时间讨论你自己的代码,你就越有信心,你的机会就越大:(-)

    编辑:根据Chad对IE错误的评论,我反对使用反射方法添加函数作为被检查对象的属性,然后重复 this -除了其他内容外,这意味着函数将显示为属性,修改正在检查的内容是一个坏主意。只需将该项作为参数传递给函数-我可以尊重地建议该名称吗? that 为了争论。

        2
  •  1
  •   Josh Stodola    15 年前

    使用 [] 而不是 Array() 因为数组可以被重写。

        3
  •  1
  •   CaffGeek    15 年前

    在您的实现中,这一行在IE中引起错误

    myInputElement.printObjectReflection=printObjectReflection;