Table of Contents
Overview
- Javascrript has an API to use Reflection similar to JAVA
- You can follow the Prototypal Chain to figure out the Object Properties and Functions
- Of course you can use Chrome Dev Tools but if you need a programatically approach continue reading
- The code may not be prefect – any comments/improvements are appreciated
- checkProperties(MammalObj) is used to walk down the Prototype Chain
JavaScript Code for Object inheritance
var Mammal = { type: 'Mammal', objectName : 'Mammal BASE Object', getDetails: function () { return("Type: " + this.type + " - ObjectName: " + this.objectName); } }; function runObjectTest9() { logMessage('--- Prototypal Inheritance via Object.create [ for details check JavaScript console ] ---'); logMessage("Global Mammal Object created via String Literals:: type: " + Mammal.type + " - getDetails(): " + Mammal.getDetails()); var MammalObj = Object.create(Mammal, { _objectName : { value: 'INITIAL MammelObj', writable: true}, objectName: { configurable: true, get: function getObjectName () { logMessage('[MammalObj objectName get]:: ' + this._objectName ); return this._objectName; }, set: function setObjectName (value) { oldVal = this._objectName; this._objectName = value; logMessage("[MammalObj objectName set]:: NEW Value: " + this._objectName + " - Old Value: " + oldVal ); } } }); logMessage('[MammalObj.objectName]:: ' + MammalObj.objectName); MammalObj.objectName = "MammalObj"; MammalObj.isWalking = false; logMessage("[MammalObj.getDetails()]:: " + MammalObj.getDetails()); logMessage("[MammalObj.type]:: " + MammalObj.type); checkProperties(MammalObj); logMessage('------------------------------------------------------------------------'); } Output: --- Prototypal Inheritance via Object.create [ for details check JavaScript console ] --- Global Mammal Object created via String Literals:: type: Mammal - getDetails(): Type: Mammal - ObjectName: Mammal BASE Object [MammalObj objectName get]:: INITIAL MammelObj [MammalObj.objectName]:: INITIAL MammelObj [MammalObj objectName set]:: NEW Value: MammalObj - Old Value: INITIAL MammelObj [MammalObj objectName get]:: MammalObj [MammalObj.getDetails()]:: Type: Mammal - ObjectName: MammalObj [MammalObj.type]:: Mammal [MammalObj objectName get]:: MammalObj
Implementation of Reflection Code
function checkProperties(o) { level =1 ; checkPropertiesPrototype(o,level); } var endOfPrototypeChainReached = false; function checkPropertiesPrototype(oProto,level) { // limit the Prototype Chain depth if ( level === 10) { logMessage("Prototype Chain > 10 : termination - Check for CodeBUGS !"); return; } /* * Abort walking down the Property Chain action when we reach the Object.prototype object * Note: Object.getPrototypeOf returns null when we reach the TOP Level Object.prototype object */ var o = oProto; var prefix = getPrefix(level*2) + " [" + o.objectName + ", level:" + level + "]"; var oProtoNext = Object.getPrototypeOf(oProto); if ( !oProtoNext) { // o.objectName is undefined for Object.prototype - Fix this prefix = getPrefix(level*2) + " [Object.prototype, level:" + level + "]"; // logMessage(prefix + " End of protoype Chain reached: Level: " + level); // Mark that we have reached the END of our Prototype Chain endOfPrototypeChainReached = true; return; } logMessage("--- Detailed ProtoType Function walking down the Prototype Chain - Level: " + level + '---'); Object.getOwnPropertyNames(o).forEach(function(val) { var objRef = o[val]; var foundIt = ""; var p = Object.getPrototypeOf(objRef); /* JavaScript has 5 primitives: Number, String, Boolean ,Undefined, Null [ Anything else is considered an object ] Object.getPrototypeOf(objRef) returns NULL for Primitives like Number, String, Boolean ,Undefined, Null */ var foundFunc = false; if ( typeof(objRef) === 'function') { foundIt = "[Found a FUNCTION]"; foundFunc = true; } else if ( typeof(objRef) === 'object') { foundIt = "[Found an OBJECT]"; } /* Object Properties: Data Descriptor : configurable, enumerable, value, writable Accessor descriptor : configurable, enumerable, set, get */ var propRes = "Oops- check getOwnPropertyDescriptor Code"; d = Object.getOwnPropertyDescriptor(o, val); if ( d ) { if ( !d.get || !d.set ) { propRes = " - Data Descriptor: Configurable: " + d.configurable + " - Enumerable: " + d.enumerable + " - Writable: " + d.writable + " - Value: " + d.value; } else { propRes = " - Accessor Descriptor: Configurable " + d.configurable + " - Enumerable " + d.enumerable + " - Set: " + d.set + " - Get: " + d.get; } } if (foundFunc) { logMessage(prefix + foundIt + " - Function Name: " + val + " - Type: " + typeof(objRef) + " - getPrototypeOf: " + p + " - Constructor: " + objRef.constructor + "\n" + prefix + propRes); } else { logMessage(prefix + foundIt + " - Property Name: " + val + " - Value: " + objRef + " - Type: " + typeof(objRef) + " - getPrototypeOf: " + p + " - Constructor: " + objRef.constructor + "\n" + prefix + propRes); } var oProto = Object.getPrototypeOf(o); // Dont walk down the Prototype Chain more than ONCE if ( !endOfPrototypeChainReached) checkPropertiesPrototype(oProto,level+1); }); level++; } function getPrefix(len) { var eStr = ''; while( eStr.length < len ) { eStr = eStr + ' '; } return eStr; }
Output from Reflection Script
--- Detailed ProtoType Function walking down the Prototype Chain - Level: 1--- [MammalObj, level:1] - Property Name: _objectName - Value: MammalObj - Type: string - getPrototypeOf: - Constructor: function String() { [native code] } [MammalObj, level:1] - Data Descriptor.: Configurable: false - Enumerable: false - Writable: true - Value: MammalObj --- Detailed ProtoType Function walking down the Prototype Chain - Level: 2--- [Mammal BASE Object, level:2] - Property Name: type - Value: Mammal - Type: string - getPrototypeOf: - Constructor: function String() { [native code] } [Mammal BASE Object, level:2] - Data Descriptor.: Configurable: true - Enumerable: true - Writable: true - Value: Mammal [Mammal BASE Object, level:2] - Property Name: objectName - Value: Mammal BASE Object - Type: string - getPrototypeOf: - Constructor: function String() { [native code] } [Mammal BASE Object, level:2] - Data Descriptor.: Configurable: true - Enumerable: true - Writable: true - Value: Mammal BASE Object [Mammal BASE Object, level:2][Found a FUNCTION] - Function Name: getDetails - Type: function - getPrototypeOf: function () {} - Constructor: function Function() { [native code] } [Mammal BASE Object, level:2] - Data Descriptor.: Configurable: true - Enumerable: true - Writable: true - Value: function () { return("Type: " + this.type + " - ObjectName: " + this.objectName); } [MammalObj, level:1] - Property Name: objectName - Value: MammalObj - Type: string - getPrototypeOf: - Constructor: function String() { [native code] } [MammalObj, level:1] - Accessor Descriptor: Configurable true - Enumerable false - Set: function setObjectName(value) { oldVal = this._objectName; this._objectName = value; logMessage("[MammalObj objectName set]:: NEW Value: " + this._objectName + " - Old Value: " + oldVal ); } - Get: function getObjectName() { logMessage('[MammalObj objectName get]:: ' + this._objectName ); return this._objectName; } [MammalObj, level:1] - Property Name: isWalking - Value: false - Type: boolean - getPrototypeOf: false - Constructor: function Boolean() { [native code] } [MammalObj, level:1] - Data Descriptor.: Configurable: true - Enumerable: true - Writable: true - Value: false