Will closure create references to every object outer even when I don't
explicitly use them?
example:
function outer () {
var div = document.createElement("div");
function inner() {
var a,b,c.... and do something blahblah without div;
}
outer = inner();
return inner;
}
In this case, I still have a memory leak?
On Sat, Dec 25, 2010 at 10:44 AM, Garrett Smith <[email protected]> wrote:
> On 12/24/10, fernando trasvina <[email protected]> wrote:
>>
>> On Dec 24, 2010, at 6:43 PM, Garrett Smith wrote:
>>
>>> On 12/24/10, Michael Haufe (TNO) <[email protected]> wrote:
>>>> On Dec 24, 3:05 pm, Garrett Smith <[email protected]> wrote:
>>>>
>>>>> I rather have it one way or the other. e.g.
>>>>>
>>>>> makePoint(x, y);
>>>>>
>>>>> - OR -
>>>>>
>>>>> new Point(x, y);
>>>>>
>>>>> I just don't like seeing any extra if/else in the code. I also don't
>>>>> want to handle the case where somebody might be relying on an anomaly
>>>>> of calling the constructor as a function call.
>>>>
>>>> If defensive programming isn't necessary, of course. But since JS
>>>> can't statically enforce such things it may be necessary to do so.
>>>>
>>> If a factory is used, then that's irrelevant. Toy example:
>>>
>>> function getAPoint(x, y) {
>>>
>>> }
>>> The worst the client could do would be to use `new getAPoint`. That
>>> would be a problem if the API expects `this` to be global object.
>>>
>>> Methods can be shared in scope, but the x and y properties can be
>>> instance properties.
>>>
>>> function getAPoint(x, y) {
>>> function distanceFromOrigin() {
>>> return Math.sqrt((this.x * this.x) + (this.y * this.y));
>>> }
>>> getAPoint = function(x, y) {
>>> return {
>>> x : x,
>>> y : y,
>>> distanceFromOrigin: distanceFromOrigin
>>> };
>>> };
>>> return getAPoint(x, y);
>>> }
>>> getAPoint(4, 0).distanceFromOrigin();
>>
>> I would say that coding this way should not be done unless there is an
>> extreme requirement for it.
>>>
>>> The downside to that is `distanceFromOrigin` is hanging off the VO, so
>>> it looks like a private static method, so what is `this`?
>>>
>>> It might be OK to "leak" a little implementation detail in this case:
>>>
>>> function getAPoint(x, y) {
>>> function Point(x, y) {
>>> this.x = +x;
>>> this.y = +y;
>>> }
>>> Point.prototype = {
>>> distanceFromOrigin : function() {
>>> return Math.sqrt((this.x * this.x) + (this.y * this.y));
>>> }
>>> };
>>>
>>> getAPoint = function(x, y) {
>>> return new Point(x, y);
>>> };
>>>
>>> return getAPoint(x, y);
>>> }
>>
>> this should be done this way. you should not be defining the constructor
>> function every time you run your factory,
>
> You're making a statement about the code that is false. The example
> uses a technique that is known as "function rewriting" or "russian
> doll" or I've explained it with more elaboration below.
>
> this what is
>> really doing is creating a new constructor function every time and building
>> an instance for it completely useless because because
>> then how would you do instanceof? never put this type of closures for
>> factories unless really needed.
>>
>
> Your conclusion follows your analysis, which unfortunately is
> incorrect. Please see my explanation below.
>
>> var Point = function(){};
>>
>> var getAPoint = function(x,y){
>> return new Point(x,y);
>> }
>>
> What's missing from that example?
>
> Here is my explanation:
>>>
>>> The Point constructor is cached on the VO of the outer getAPoint.
>>> Outer getAPoint identifier gets assigned to inner getAPoint identifier
>>> but the scope chain of the inner getAPoint function has the Point
>>> constructor and prototype.
>>>
>
> That's my explanation. VO = "Variable Object".
>
> I've added two alerts and some explanatory comments. Generally, I
> would not want to see such comments cluttering up the code but I added
> them to help explain how the code works.
>
> The following example has two alerts: one in the outer "getAPoint"
> function and one in the inner function, which is reassigned to
> "getAPoint". Only the first call to getAPoint(1, 2); results in the
> `getAPoint` function being called. When that getAPoint function is
> first called, it reassigns the
>
> function getAPoint(x, y) {
> alert('in outer getAPoint');
> function Point(x, y) {
> this.x = +x;
> this.y = +y;
> }
> Point.prototype = {
> distanceFromOrigin : function() {
> return Math.sqrt((this.x * this.x) + (this.y * this.y));
> }
> };
>
> // When this statement is reached,
> // getAPoint is resolved up the scope chain
> // and assigned the value of the FunctionExpression.
> // That FunctionExpression's scope chain has Point on it,
> // and so the Point constructor can still be accessed.
> getAPoint = function(x, y) {
> alert("in inner getAPoint");
> return new Point(x, y);
> };
>
> // This statement is called in the original getAPoint
> // function. That only happens once because the
> // previous statement changed the value of getAPoint
> // to point to the inner function.
> return getAPoint(x, y);
> }
>
> getAPoint(4,0); // outer alert, inner alert.
> getAPoint(4,0); // inner alert.
>
> You can see that the outer function is called only once. The `Point`
> constructor function is cached on the scope of the inner function.
> That's what we want here.
>
> The caveat to this pattern is that you get caching of everything on
> the VO automatically. Be careful and set things you don't need to keep
> around null. Otherwise, you'll have memory leaks.
>
> A common memory leak example is when the outer function creates
> elements to perform a feature test, saving those elements on the VO.
> Those identifiers are available on the scope chain of any nested
> functions. The reference to the element from that identifier can be
> broken by assinging those identifiers the value `null`.
>
> function outer() {
> var div = document.createElement("div");
> function inner() {
> // alert(div); // Its available on the scope chain
> }
> outer = inner;
> return inner();
> }
>
> That memory leak of `div` can be fixed by either setting `div` to null
> or by declaring `div` inside a function that doesn't expose any nested
> functions (so that `div` can be GC'd when that function completes).
>
> [snipped signatures]
> --
> Garrett
>
> --
> To view archived discussions from the original JSMentors Mailman list:
> http://www.mail-archive.com/[email protected]/
>
> To search via a non-Google archive, visit here:
> http://www.mail-archive.com/[email protected]/
>
> To unsubscribe from this group, send email to
> [email protected]
>
--
Lai, Yu-Hsuan
--
To view archived discussions from the original JSMentors Mailman list:
http://www.mail-archive.com/[email protected]/
To search via a non-Google archive, visit here:
http://www.mail-archive.com/[email protected]/
To unsubscribe from this group, send email to
[email protected]