Prev: Microsoft Visual Web Developerr
Next: FAQ Topic - What is the Document Object Model (DOM)? (2010-05-17)
From: RobG on 17 May 2010 20:00 On May 18, 3:59 am, williamc <n...(a)nowhere.net> wrote: [...] > Working through the example below helped me when I was reading the Zakas > book not too long ago. From a notes page... > > * * * > > 4. Inner functions that retain values from outer functions possess the > last value from the outer function. Not so. The inner function has the outer function's variable object on its scope chain, the identifier - i - will resolve to it if no local variable shadows it. If the value of the variable changes, then its value changes in the inner function too, e.g. var outer = (function () { var x; return { getX: function () { return x; }, setX: function(val) { x = val; } } })(); // Check the value of x alert(outer.getX()); // undefined // Set the value of x to a string outer.setX('foo'); // Check the value of x alert(outer.getX()); // foo So the value isn't "set" when the function exits. The value is whatever it is when it is read and can be changed by some other closure (emulating a privileged method). > This can lead to unexpected results > as demonstrated in the first function below, which the programmer > expected to return an array of functions which each will return the > value of their array index. Instead, each function returns 5. Unexpected only if the programmer isn't aware of how closures work in ECMAScript. > The second function creates the desired array of functions. Zakas: "The > anonymous function has one argument, num, which is the number that the > result function should return. Since function arguments are passed by > value, the current value of i is copied into the argument num." More misdirection. They are always references, but the *value* might be a primitive or an object. Primitives are immutable, you can't modify them, you can only assign a new one, so: // With primitives var a = 5, b = a; // a and b == 5 b = 6; // b is assigned a new value, a is still == 5 // With objects var o = {}, p = o; // o and p == object assigned to o p = {}; // p is assigned a new object, o hasn't changed The difference is that you can modify an object's properties, so: var o = {}, p = o; // o and p == object assigned to o p.x = 'foo'; alert(o.x); // foo The the concept that "function arguments are passed by value" might be kind of true if function arguments are always primitives, but they aren't. > function createFunctions() { > var result = new Array(); > for (var i = 0; i < 5; i++) { > result[i] = function() { > return i; > }; > } > return result; > } > arrTest = createFunctions(); > alert(arrTest[2]()); // 5, not 2! > > function createFunctions2() { > var result = new Array(); > for (var i = 0; i < 5; i++) { > result[i] = function(num) { > return function() { > return num; > }; > }(i); > } > return result; > } > arrTest = createFunctions2(); > alert(arrTest[2]()); // now it's 2 Because of the new closure with num. Variable i is still there on the inner function's scope chain, replace: return num; with return i; and you get 5 again. -- Rob
From: RobG on 17 May 2010 20:53 On May 18, 3:56 am, Matt Kruse <m...(a)thekrusefamily.com> wrote: > On May 16, 5:44 pm, Eleandor <vanbeurden.b...(a)gmail.com> wrote: > > > what I'm trying to achieve is to create a function that uses the > > actual value of i, at the moment when the onclick function is created. > > So "Display 5" should actually display 5, using the literal value of i > > when the function is created, instead of the value of i at the time of > > execution. > > elm.onclick = (function(inner_i) { > return function() { > self.shout(inner_i); > } > > })(i); > > Be careful for memory leaks... Yes, forgot to mention that. They can be avoided for the most part by setting: elm = null; in the function where elm is declared just before it ends. -- Rob
From: Stefan Weiss on 17 May 2010 21:39 On 17/05/10 00:44, Eleandor wrote: > Person = (function() { > return function() { > var self = this; .... Minor nitpick: self is not a good variable name in browser scripting; it's usually an alias for the window object. It won't cause a problem in your example, but it could confuse people who see a call to "self.shout()" before they see the assignment above. -- stefan
From: Thomas 'PointedEars' Lahn on 18 May 2010 06:52 RobG wrote: > On May 18, 3:59 am, williamc <n...(a)nowhere.net> wrote: > [...] >> The second function creates the desired array of functions. Zakas: "The >> anonymous function has one argument, num, which is the number that the >> result function should return. Since function arguments are passed by >> value, the current value of i is copied into the argument num." > > More misdirection. They are always references, What do you mean by "they" here? > but the *value* might be a primitive or an object. No, the value can be a primitive value or an object reference. You cannot access an object directly, you need a reference to it. As a result, there can be multiple references to the same object. The object may be subject to garbage collection if it is no longer referred, i.e. there are no more references to it (much like with hardlinks). > The the concept that "function arguments are passed by value" might be > kind of true if function arguments are always primitives, but they > aren't. Zakas' premise is right here; you are not. Object references are values. See also <https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Functions>, which was agreed on here. PointedEars -- Use any version of Microsoft Frontpage to create your site. (This won't prevent people from viewing your source, but no one will want to steal it.) -- from <http://www.vortex-webdesign.com/help/hidesource.htm> (404-comp.)
From: Thomas 'PointedEars' Lahn on 18 May 2010 07:26
Stefan Weiss wrote: > Eleandor wrote: >> Person = (function() { >> return function() { >> var self = this; > ... > > Minor nitpick: self is not a good variable name in browser scripting; > it's usually an alias for the window object. It won't cause a problem in > your example, but it could confuse people who see a call to > "self.shout()" before they see the assignment above. It is not "usually an alias for the window object", it is a property of Window instances or their prototype to refer to the instance. A Window instance's prototype may be in the prototype chain of the ECMAScript Global Object (this is the case with client-side JavaScript 1.8.2 in Gecko 1.9.2.3). Since to my knowledge it is unnecessary to access the `self' property of Window instances, I can see no cause for confusion here. Indeed, the declaration follows the pattern of several other OOPLs, including most notably, IIUC, Smalltalk which influenced the prototype-based Self programming language (where you can omit `self') which influenced JavaScript (unfortunately, Brendan Eich apparently did not see the importance of the `self' keyword in JavaScript's predecessors). However, in this case that assignment probably should be moved before the `for' loop. There is no need (and perhaps no want) of the `self' identifier to be in the scope of the returned function. But the function expression returning a function when called is quite pointless and therefore inefficient here to begin with; the assignment of a function expression, or a function declaration would suffice as there are no bound variables in the outer scope. PointedEars -- Prototype.js was written by people who don't know javascript for people who don't know javascript. People who don't know javascript are not the best source of advice on designing systems that use javascript. -- Richard Cornford, cljs, <f806at$ail$1$8300dec7(a)nes.demon.co.uk> |