Это достойный пример реализации отражения javascript? - PullRequest
1 голос
/ 17 сентября 2009

Это для собеседования при приеме на работу, и мне бы очень хотелось, если бы кто-то мог взглянуть на это и сказать, делаю ли я какие-либо большие ошибки. Здесь был вопрос:

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 ]

1 голос
/ 17 сентября 2009

В вашей реализации эта строка вызывает ошибку в IE

myInputElement.printObjectReflection = printObjectReflection;

1 голос
/ 17 сентября 2009

Код выглядит нормально. Если вы действительно хотите произвести на них впечатление, рассмотрите возможность объединения средства просмотра результатов, которое представляет информацию в списке (или таблице) и позволяет щелкать объекты и массивы, после чего они отображаются во вложенном списке (или таблице).

Это может показаться излишним для вопроса об интервью, но на самом деле это довольно просто сделать и демонстрирует хорошее понимание DOM.

Что еще более важно, он предоставляет что-то, что может подсказать дополнительные вопросы от интервьюеров. Помните: у них будет только определенное количество времени, и это будет держать их вопросы сосредоточенными на фрагменте кода, который вы полностью понимаете, уменьшая риск того, что они зададут вам вопрос о чем-то, чего вы не знаете так хорошо.

Чем больше вы можете заставить их тратить время на разговор о вашем собственном коде, тем увереннее вы себя чувствуете и тем больше у вас шансов: -)

РЕДАКТИРОВАТЬ: следуя комментарию Чада об ошибке IE, я бы поспорил с использованием подхода отражения, который заключается в добавлении функции в качестве свойства исследуемого объекта и последующей итерации по this - кроме всего прочего, это означает, что функция будет отображаться как свойство, и изменение проверяемого объекта - плохая идея. Просто передайте элемент в качестве аргумента функции - могу ли я с уважением предложить имя that для аргумента.

1 голос
/ 17 сентября 2009

Используйте [] вместо Array(), поскольку массив можно переопределить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...