Presentation is loading. Please wait.

Presentation is loading. Please wait.

Scope And Inheritance In JScript JScript scopes are nested and allow hiding. All identifier resolution happens at run time*. When resolving an identifier,

Similar presentations


Presentation on theme: "Scope And Inheritance In JScript JScript scopes are nested and allow hiding. All identifier resolution happens at run time*. When resolving an identifier,"— Presentation transcript:

1 Scope And Inheritance In JScript JScript scopes are nested and allow hiding. All identifier resolution happens at run time*. When resolving an identifier, JScript works outward through possibly many nested scopes. Functions can contain functions! When declaring a property, there are only three possible scopes: global, function (there is no block scope like in C++!), and “attached to object”. A named property may be added to any object at any time. These are “expando” properties. (Literals are special: properties don’t stick to them.) Properties can even have names that are not valid identifiers, if “associative array” syntax is used. Most (but not all) properties are enumerable. * Caveat: All ‘function’ declarations and ‘var’ declarations “happen” on entry to the function, even though there may be executable statements that precede them.

2 All objects have an implicit reference to a prototype object. All properties of an object’s prototype are visible on the object, however they can be hidden by a property of the same name on the object. The implicit prototype is not the same as the object referred to by the prototype property. There is no way to get to an object’s implicit prototype. (‘__proto__’ under Netscape?) All functions are “classes”! Functions are constructors for their class and have a prototype property. The object referred to by this property will be come the implicit prototype of any instances of this class that are subsequently created. A “class” can “inherit” from another by setting the derived class’s prototype to an instance of the base class. This creates a prototype chain. Constructors are not chained like in C++. ‘This’ changes implicitly like in C++, but members of ‘this’ are not implicitly in scope. ‘This’ refers to the object used to invoke a function, or to global scope if the function is not attached to an object.

3 What does this all mean?? There is no class member protection! Be on your best behavior, or you know the consequences. Properties on the object act like instance members. Properties on the function (“class”) act like static members. Properties on the prototype act like? 1) copy on write instance members. 2) shared members (!?). Best for function properties. The ‘constructor’ property is not reliable and should be used with care. A class can also “inherit” from another by copying all the properties of the other class – less weird. Or, forgo inheritance. The system provided prototypes are expando: you can add methods to system types! String.trim, etc.

4 objDerived _proto_ objBase _proto_ Derived() _proto_ «expando properties» prototype Base() _proto_ «expando properties» prototype Object _proto_ «expando properties» prototype baseProto _proto_ «expando properties» constructor length objectProto _proto_ «expando properties» derivedProto _proto_ «expando properties» constructor Automatic prototype for each function. Instance of Base classInstance of Derived class Instance of Base class set as prototype for Derived class Property inherited from prototype Functions / classes System type System object at end of every prototype chain meth2 Explicitly set property Urg! Inheritance is complicated. meth1

5 // /** Creates a new stack. */ function Stack() { this.pHead=null; } // /** Pushs object on stack. obj object to put on stack */ function Stack.prototype.push(obj) { this.pHead={pThis:obj, pNext:this.pHead}; } // /** Pops top object off stack. top object on stack Error if stack is empty */ function Stack.prototype.pop() { if (null==this.pHead) { throw new Error(-1, "Can't pop from empty stack."); } var obj=this.pHead; this.pHead=obj.pNext; return obj.pThis; } // True if stack is empty. */ function Stack.prototype.isEmpty() { return null==this.pHead; } Your basic Stack class.

6 // /** Dumps the properties of the given object. * The 'constructor' property is not be processed for children of * function objects and children of a 'constructor' property. * Inherrited properties will be prefixed by * Un-enumerable properties will be prefixed by "%". (We guess which * un-enumerable properties exist.) obj object to dump. sName name to precede the dump bRecurse [optional, default=true] true if member objects * should be dumped. sPrefix [optional, default=""] string to print in front * of each line. */ function DumpObj(obj, sName, bRecurse, sPrefix) { // provide defaults for optional params if ("undefined"==typeof sPrefix) { sPrefix=""; } if ("undefined"==typeof bRecurse) { bRecurse=true; } if ("object"!=typeof obj && "function"!=typeof obj) { WScript.Echo(sPrefix+sName+": (Not an object! Type:"+(typeof obj)+")"); } else if (null==obj) { WScript.Echo(sPrefix+sName+": (null)"); } else { WScript.Echo(sPrefix+sName+":"); dumpObjImpl(obj, bRecurse, sPrefix, false); } return; // function printKey(obj, sKey, bRecurse, sPrefix, sPrefix2, bSkipCtor, bHidden) { var sType=typeof obj[sKey]; var sIntPrefix=""; if (("hasOwnProperty" in obj) && !obj.hasOwnProperty(sKey)) { } if (bHidden) { sIntPrefix+="%"; } switch (sType) { case "undefined": // don't print this property bRecurse=false; break; case "function": var sFunc=obj[sKey].toString(); var rgMatches=sFunc.match( /function\s*((?:\w+\s*\.\s*)*\w+)\s*\(/i ); var sFuncName; if (null==rgMatches) { sFuncName=sFunc; } else { sFuncName=rgMatches[1].replace(/\s*/g, ""); } WScript.Echo(sPrefix+sIntPrefix+sKey+"=["+sType+"] "+sFuncName); bSkipCtor=true; break; case "string": WScript.Echo(sPrefix+sIntPrefix+sKey+"=["+sType+"] \""+obj[sKey]+"\""); bRecurse=false; // literals can't have expandos break; case "number": case "boolean": WScript.Echo(sPrefix+sIntPrefix+sKey+"=["+sType+"] "+obj[sKey]); bRecurse=false; // literals can't have expandos break; case "object": if (null==obj[sKey]) { WScript.Echo(sPrefix+sIntPrefix+sKey+"=null"); bRecurse=false; } else { WScript.Echo(sPrefix+sIntPrefix+sKey+"=["+sType+"]"); } break; default: throw new Error(-1, "unknown type '"+sType+"'."); } if (bRecurse) { dumpObjImpl(obj[sKey], bRecurse, sPrefix2, bSkipCtor); } // function dumpObjImpl(obj, bRecurse, sPrefix, bSkipCtor) { var rgKnownProps=new Array( // skip the dynamic properties, because of possibility of unbounded recursion //"arguments", "callee", "caller", "constructor", "description", "E", "global", "ignoreCase", "index", "Infinity", "input", "lastIndex", "leftContext", "length", "lastMatch", "lastParen", "LN2", "LN10", "LOG2E", "LOG10E", "MAX_VALUE", "message", "MIN_VALUE", "multiline", "NaN", "name", "NEGATIVE_INFINITY", "number", "PI", "POSITIVE_INFINITY", "prototype", "source", "SQRT1_2", "SQRT_2", "undefined"); // first, see which of the un-enumerable props we have var rgProps=new Array(); var nIndex; for (nIndex=0; nIndex


Download ppt "Scope And Inheritance In JScript JScript scopes are nested and allow hiding. All identifier resolution happens at run time*. When resolving an identifier,"

Similar presentations


Ads by Google