这是一个体面的javascript反射示例实现吗?

时间:2009-09-17 17:18:37

标签: javascript reflection

这是一次求职面试,如果有人可以对此表示关注并说我犯了什么大错,我会很高兴。这是一个问题:

  

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>

任何人都可以发现任何令人难以置信的愚蠢错误?提前感谢熟练的眼球。

编辑:好的,这是我修改后的实施。我最终只是完全删除了hasOwnProperty检查,因为它似乎非常扼杀IE并且它不是基于hasOwnProperty限制的要求的一部分:

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>

感谢大家的帮助。它仍然无法在IE中运行,遗憾的是......如果我想出最终实现,我会发布它。

3 个答案:

答案 0 :(得分:1)

使用[]代替Array(),因为可以覆盖数组。

答案 1 :(得分:1)

在您的实现中,此行会在IE中导致错误

myInputElement.printObjectReflection = printObjectReflection;

答案 2 :(得分:1)

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

对于面试问题来说,这似乎有些过分,但实际上这很简单,并且可以很好地理解DOM。

更重要的是,它提供了一些内容来提示采访者提出进一步的问题。记住:他们只会有一定的时间,这会使他们的问题集中在你完全理解的一段代码上,从而降低他们对你不熟悉的问题打击你的风险。

你越是花时间谈论自己的代码,你就会越自信,机会就越大: - )

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