43976

Functions in global context

I understand that functions called without the "new" keyword spit out all their properties on to the global context. But I am seeing some curious behavior, with this piece of Javascript code:

function Test3() { var a=0; this.inc = function() { return ++a; }; this.noInc = function() { return a; }; this.testRef = function() { return this; }; return { inc: inc, testRef: testRef, noInc: noInc }; } var o = Test3(); // Put func properties on global context var o2 = Test3(); // Put func properties on global context (replacing properties above??) // Both "o" and "o2" maintain their own copy of "a" (closure) alert("o: " + o.inc()); alert("o: " + o.inc()); alert("o: " + o.inc()); // Will output 3 (as expected) alert(noInc()); // Output: 1 (This seems to not be affected by o.inc() calls - expected) // However... alert("o2: " + o2.inc()); alert("o2: " + o2.inc()); alert("o2: " + o2.inc()); alert("o2: " + o2.inc()); // Will output 4 (as expected) alert(noInc()); // Will output 4 (seems to share with o2), but why? alert(o === window); // false alert(o.testRef() === o); // true (I thought testRef() would be on global context?) alert(o.testRef() === window); // false (^^) alert(o2 === window); // false alert(o2.testRef() === o2); // true (I thought testRef() would be on global context?) alert(o2.testRef() === window); // false (^^) alert(testRef() === window); // true (How come this is here? Look at comments above) <ol> <li>

When we call var o = Test(), what exactly happens here? What context does Test() execute in. Since the new keyword is missing, I believe, this inside Test3() would refer to window? What does "o" refer to? Is it simply a variable declared on the global context?

</li> <li>

If above is true, then how are o and o2 able to maintain separate copies of Test3's local variable "a". I understand that we have closure in action here, but then how come, "o2" and "window" share the same copy of the variable "a", but NOT "o"

</li> <li>

When I do var o = Test3() and then do alert(o.testRef() === window), it says false. So after executing:

var o = Test3(); var o2 = Test3(); </li> </ol>

There seems to be 3 copies of the properties from Test3(). One on "o", another one on "o2" and one on the global context.

But how can there be any on "o" and "o2" - I am not calling Test3() with the "new" keyword, so this should only refer to global context?

Answer1:

Every time you call Test3, the inc, noInc and testRef functions are reassigned to window with a different a (which is initialized to 0 at the top of the function.)

window and o2 share the same a because the functions were reassigned to window when o2 got the return value and not o1.

Example from NodeJS REPL (note in NodeJS, the global object is referenced by global instead of window, but otherwise there shouldn't be any difference):

> function Test3() { ... var a=0; ... ... this.inc = function() { ... return ++a; ... }; ... ... this.noInc = function() { ... return a; ... }; ... ... this.testRef = function() { ... return this; ... }; ... ... return { ... inc: inc, ... testRef: testRef, ... noInc: noInc ... }; ... } undefined > var o = Test3(); undefined > o.inc() 1 > o.inc() 2 > o.inc() 3 > noInc() 3

Because Test3 was only called once and set to o1, both the global scope and o1 share an a. Now watch as I call Test3 again:

> Test3() { inc: [Function], testRef: [Function], noInc: [Function] } > noInc() 0 > o.noInc() 3

The functions are reassigned to the global object, with an a of 0, while o keeps the previous a.

Answer2:

Your code can be reduced to:

var inc, noinc, a = 0, a2 = 0; inc = function () { a += 1; } noinc = function () { return a; } inc(); inc(); inc(); noinc(); // 3 inc = function () { a2 += 1; } noinc = function () { return a2; } // now inc and noinc are bound to a2 noinc(); // 0, yours gives 1?

So basically you're overriding the definition of inc and noinc bound to a different a.

If instead of var a = 0 you had this.a = this.a || 0 you would bind to the same a.

Recommend

  • How to trigger ServiceNow workflow from ui action?
  • How to replace double/multiple slash to single in url
  • The name 'ViewData' does not exist in the current context
  • How do you close open files using Swift?
  • Add-In Commands Ribbon shows in Excel Online but not in Excel for Windows
  • How can I refer to multiple databases using the same looping vector in R?
  • c# parsing xml with and apostrophe throws exception
  • Gradle dynamic flavor
  • plot if col A has substring
  • Partial String Replacement using PowerShell
  • Scala's collect inefficient in Spark?
  • How to replace one set of color 'shades' with another set
  • Any function in numpy/pandas/python to search and replace
  • Can someone please explain how this implementation of bucket sort works?
  • Crafting a LINQ based solution to determine if a set of predicates are satisfied for a pair of colle
  • Creating an Order Column for encrypted data
  • Prolog Ambiguous Output
  • Mocha throws unexpected token error for ES6 object spread operator
  • Add reference to ASP.NET 5 Class Library from Framework 4.5 Class Library Project
  • How to display special characters in SQL server 2008?
  • Most efficient way to move table rows from one table to another
  • Execute scripts AJAX returns
  • std::remove_copy_if_ valgrind bytes in block are possibly lost in loss record
  • MySQL Order by column = x, column asc?
  • How to use JavaScript to determine whether a file exists in a directory?
  • PHP buffered output depending on server setting?
  • FileReader+canvas image loading problem
  • Update CALayer sublayers immediately
  • Is possible to count alias result on mysql
  • Incrementing object id automatically JS constructor (static method and variable)
  • Check if a string to interpolate provides expected placeholders
  • Deserializing XML into class C#
  • Function pointer “assignment from incompatible pointer type” only when using vararg ellipsis
  • XCode can't find symbols for a specific iOS library/framework project
  • Compare two NSDates in iPhone
  • python draw pie shapes with colour filled
  • XCode 8, some methods disappeared ? ex: layoutAttributesClass() -> AnyClass
  • Does armcc optimizes non-volatile variables with -O0?
  • Running Map reduces the dimensions of the matrices
  • How to Embed XSL into XML