This is for a job interview and I'd love it if someone could put an eyeball on this and say if I'm making any big mistakes. Here was the question:
1) Assume we're developing a JS-based debugger, similar to Firebug, and we need a way to inspect JS objects and elements. Write a routing that takes an object/element as input and list out its properties (such as attributes, methods, etc.), values and data types.
Here's my implementation:
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
And a sample use:
<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>
Any incredibly foolish errors anyone can spot? Thanks in advance for the skilled eyeball.
EDIT: Ok, here's my revised implementation. I did end up just completely removing the hasOwnProperty check entirely since it seems to choke IE terribly and it's not really a part of the requirements to limit based on 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
And the new call:
<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>
Thanks everyone for the help. It still doesn't work in IE, sadly... if I come up with a final implementation that does, I will post it.