Editing
JavaScript/Notes/Scope
(section)
Jump to navigation
Jump to search
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
=Scope Chain and Identifier Resolution.= A "closure" is function scope that has a binding to its containing scope. == Functions That Return Functions == [http://jsbin.com/ojEfIDay/1/edit Functions That Return Functions] == Example == [http://jsbin.com/OxOSObuc/1/edit jsbin] <source lang="javascript"> (function () { var currentScope = 1, one = 'scope1'; alert(currentScope); (function () { var currentScope = 2, two = 'scope2'; alert(currentScope); (function () { var currentScope = 3, three = 'scope3'; alert(currentScope); alert(one + two + three); // climb up the scope chain to get one and two }()); }()); }());</source> == Example == [http://jsbin.com/OxOSObuc/1/edit jsbin] <source lang="javascript"> function outer() { var secret = 1; function inner() { return secret; } return inner; } var inner = outer(); var result = inner(); console.log(result); // explain the result. </source> == Timers == [http://jsbin.com/IwOwEjoQ/2/edit setInterval and Scope] === QUIZ === [http://ejohn.org/apps/learn/#62 #62: QUIZ: Fix the broken closures in this loop!] === Event Handler === Fix the example below so that when show is called, the alert box displays the <source lang="javascript"> var dialogBox = { isShown : false, show : function() { alert(this.isShown); } }; document.body.onclick = dialogBox.show; // explain what happens when body is clicked. </source> http://jsbin.com/uTucAMeH/1/edit <!-- source lang="javascript"> var dialogBox = { isShown : false, show : function() { alert(this.isShown); } }; document.body.onclick = function() { dialogBox.show(); }; </source --> == Block Scope == Normally, the only way to create scope in JavaScript is by creating a function. However, a little known anomaly is that the catch block augments the scope with a new object. <source lang="javascript"> function x() { var result = typeof x; try { y; // ReferenceError } catch(x) { result = [result, x]; } result.push(typeof x); alert(result); } </source> http://jsbin.com/EveMAVIP/1/edit <h3>Catch Block Identifier</h3> In the above code, a new DeclarativeEnvironment is dynamically created when the catch block is entered, with the Identifier `x` being added to its scope, and that scope being used for the duration of the catch block. See: [http://ecma-international.org/ecma-262/5.1/#sec-12.14 Ecma-262 § 12.14]. == Variable Scope Inside function == Richard Cornford explains Variable Instantiation, as defined in ECMA-262 r3. http://bytes.com/topic/javascript/answers/556357-variable-scope-inside-function-did-i-get-correctly#post2171544 == Module Pattern == Very common one-off pattern. Must know! <source lang="javascript"> var page = function () { // Private members. var msg = "secret"; function positionPanel(panel) { } return { myPublicProperty: "Accessible as page.myPublicProperty.", myPublicMethod: function () { return msg; }, showPanel : function(id) { var panel = document.getElementById(id); if(!panel) return; positionPanel(panel); panel.style.display = "block"; } }; }(); </source> http://jsbin.com/oYUhOCic/1/edit == Declaration Binding Instantiation == [http://www.ecma-international.org/ecma-262/5.1/#sec-10.5 § 10.5] Every execution context has an associated VariableEnvironment. Variables and functions declared in ECMAScript code evaluated in an execution context are added as bindings in that VariableEnvironment’s Environment Record. For function code, parameters are also added as bindings to that Environment Record. From [https://groups.google.com/forum/#!topic/jsmentors/JnHM3Pvesp8 global object property access]. <blockquote> Consider the following "weird" behavior with the global object: <source lang="javascript"> console.log(window.foo); // this returns undefined console.log(this.foo); // this returns undefined console.log(foo); // this is a reference error </source> Accessing a non existent property on an object should return undefined... which accounts for the first two cases... but whats going on in the third case? </blockquote> the ECMAScript specification on <code>[http://www.ecma-international.org/ecma-262/5.1/#sec-15.11.6.3 ReferenceError]</code> explains that <code>ReferenceError</code> is also thrown in strict mode when making an assignment to an undeclared identifer. <source lang="javascript"> (function(){ "use strict"; erwt = 1; })(); // ReferenceError </source> Back to the example, getting a property off an object, the prototype chain is searched. When that happens, if the property is not found, then <code>undefined</code> results. But with scope chain resolution, when the property is not resolved, an error results. <blockquote style="white-space:pre"> | 11.1.2 Identifier Reference | An Identifier is evaluated by performing Identifier Resolution | as specified in 10.3.1. The result of evaluating an Identifier | is always a value of type Reference. </blockquote> ... <blockquote style="white-space:pre"> | 10.3.1 Identifier Resolution | Identifier resolution is the process of determining the binding of an | Identifier using the <code>LexicalEnvironment</code> of the running execution context. </blockquote> <blockquote style="white-space:pre"> > console.log(foo); // this is a reference error > </blockquote> <p>Identifier <code>foo</code> is resolved to a Reference with null as the base object. In ES5, it looks as if it is a Reference with base object as <code>undefined</code>. With either spec, the result will be the same: <code>ReferenceError</code>. ES5 gets a little fancy with the explanation. <blockquote style="white-space:pre"> > The Mozilla docs on Reference error simply state: > > A ReferenceError is thrown when trying to dereference a variable that > has not been declared. > </blockquote> They mean that when you try and get the value of an Identifier in a PrimaryExpression and the Identifier is not resolved, then the base object is null (or now <code>undefined</code>) that the attempt to get at the value is going to result in a <code>ReferenceError</code>. So when you have an Expression like: <pre> console.log(foo); </pre> or even just a PrimaryExpression: <pre> foo // a PrimaryExpression. </pre> Identifier <code>foo</code> must be first resolved. The base object for that value is null (or so"undefined") and the when the expression is evaluated, it tries to get the value, and then finds the base object is null and throws a ReferenceError is thrown. | 8.7.1 GetValue (V) | | 1. If Type(V) is not Reference, return V. | 2. Let base be the result of calling GetBase(V). | 3. If IsUnresolvableReference(V), throw a ReferenceError exception. ... | IsUnresolvableReference(V). Returns true if the base value | is undefined and false otherwise. The MDC docs might not say it, and you didn't ask, either, but in strict code, assignment to undeclared Identifier will result in referenceerror too. <blockquote style="white-space:pre"> > I realize accessing a non existent property on an object should return > undefined... which accounts for the first two cases... but whats going > on in the third case? </blockquote> An Identifier resolution was performed on the scope chain. Just remember the difference when getting a property fails: With object properties - the prototype chain is used and the result is undefined. With unqualified Identifiers, the scope chain is searched in the result is ReferenceError. ==Omitting var in VariableDeclaration== Assignment without var is not a variable declaration. <pre> foo = 1; </pre> The identifier foo must be resolved up the scope chain (see 11.13.1 Simple Assignment, also below). If foo is not found, a foo property is created on the global object (see 8.7.2 <code>PutValue</code>). This can cause further problems in IE with IE's global scope polluter. See: [https://groups.google.com/forum/#!msg/comp.lang.javascript/K3PD0gJgUxY/0R0OZvHs2K4J Extra Properties: The Element Id Resolver Object] <pre> 11.13.1 Simple Assignment (= ) The production AssignmentExpression : LeftHandSideExpression = AssignmentExpression is evaluated as follows: 1. Evaluate LeftHandSideExpression. 2. Evaluate AssignmentExpression. 3.Call GetValue(Result(2)). 4.Call PutValue(Result(1), Result(3)). 5.Return Result(3). </pre> Step 4 leads to <code>PutValue(foo, 1)</code> <pre> 8.7.2 PutValue(V, W) 1. If Type(V) is not Reference, throw a ReferenceError exception. 2. Call GetBase(V). 3. If Result(2) is null, go to step 6. 4. Call the [[Put]] method of Result(2), passing GetPropertyName(V) for the property name and W for the value. 5. Return. 6. Call the [[Put]] method for the global object, passing GetPropertyName(V) for the property name and W for the value. 7. Return. </pre> Step 2, <code>GetBase(v)</code> is <code>null</code>, so that leads to step 6. That leads to <code><nowiki>[[Put]]</nowiki></code> (foo, 1) on the global object. <pre> 8.6.2.2 [[Put]](P, V) When the [[Put]] method of O is called with property P and value V, the following steps are taken: 1. Call the [[CanPut]] method of O with name P. 2. If Result(1) is false, return. 3. If O doesn't have a property with name P, go to step 6. 4. Set the value of the property to V. The attributes of the property are not changed. 5. Return. 6. Create a property with name P, set its value to V and give it empty attributes. 7. Return. Note, however, that if O is an Array object, it has a more elaborate [[Put]] method (15.4.5.1). </pre> Note step 6: Create a property with name P, set its value to V and give it empty attributes. Global object properties (user-defined ones, at least) are <nowiki>[[Configurable]]</nowiki>, variables, global or otherwise, are not. User-defined properties are, by default, <nowiki>[[Configurable]]</nowiki>, which means that they can be deleted. If code is eval code, then let configurableBindings be true else let configurableBindings be false. http://www.ecma-international.org/ecma-262/5.1/#sec-10.5 == Assignment == Find Two Examples of Closures in code.
Summary:
Please note that all contributions to Noisebridge are considered to be released under the Creative Commons Attribution-NonCommercial-ShareAlike (see
Noisebridge:Copyrights
for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource.
Do not submit copyrighted work without permission!
To protect the wiki against automated edit spam, we kindly ask you to solve the following CAPTCHA:
Cancel
Editing help
(opens in new window)
Navigation menu
Personal tools
Not logged in
Talk
Contributions
Log in
Request account
Namespaces
Page
Discussion
English
Views
Read
Edit
View history
More
Search
Dig in!
Noisebridge
- Status: MOVED
- Donate
- ABOUT
- Accessibility
- Vision
- Blog
Manual
MANUAL
Visitors
Participation
Community Standards
Channels
Operations
Events
EVENTS
Guilds
GUILDS
- Meta
- Electronics
- Fabrication
- Games
- Music
- Library
- Neuro
- Philosophy
- Funding
- Art
- Crypto
- Documentation/Wiki
Wiki
Recent Changes
Random Page
Help
Categories
(Edit)
Tools
What links here
Related changes
Special pages
Page information