1 / 6

Scope And Inheritance In JScript

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!

carrie
Download Presentation

Scope And Inheritance In JScript

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

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

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

  6. //----------------------------------------------------------------//---------------------------------------------------------------- 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<rgKnownProps.length; nIndex++) { if (rgKnownProps[nIndex] in obj) { rgProps.push(rgKnownProps[nIndex]); } } // second, see which enumerable props we have var rgProps2=new Array(); var sKey; for (sKey in obj) { rgProps2.push(sKey); // remove enumerable props from un-enumerable props for (nIndex=0; nIndex<rgProps.length; nIndex++) { if (sKey==rgProps[nIndex]) { rgProps.splice(nIndex, 1); break; } } } // combine the lists var nHiddenCount=rgProps.length; var bHidden; rgProps=rgProps.concat(rgProps2); // print each element var sPrefix1=sPrefix+"|---"; var sPrefix2=sPrefix+"| "; for (nIndex=0; nIndex<rgProps.length; nIndex++) { bHidden=nIndex<nHiddenCount; if (nIndex+1==rgProps.length) { sPrefix1=sPrefix+"\\---"; sPrefix2=sPrefix+" "; } if ("constructor"!=rgProps[nIndex]) { printKey(obj, rgProps[nIndex], bRecurse, sPrefix1, sPrefix2, bSkipCtor, bHidden); } else if (false==bSkipCtor) { printKey(obj, "constructor", bRecurse, sPrefix1, sPrefix2, true, bHidden); } else { //WScript.Echo("skip ctor"); // skipped inside functions and ctors } } } } Reward for sitting through that: An object dumper! //-------------------------------------------------------------------- /** 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.) * @param obj object to dump. * @param sName name to precede the dump * @param bRecurse [optional, default=true] true if member objects * should be dumped. * @param 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)) { sIntPrefix+="@"; } 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); } } (continuing…)

More Related