Static function variables with 'this' bleed into children

I thought this was a safe way to define function-bound static variables and do some init only once

function myfunc(force) {
  if ((typeof this.Init === 'undefined') || (force)) {this.Init = true;}

But then chasing some bug I realized that if myfunc is called from another function that also has defined this.Init, it breaks down as this was referencing that parent caller function, so ↓ prints "OnCloseTab" instead of undefined

function ttt() {
  dbg('ttt='+this.name);
}
function OnCloseTab(closeTabD) {
this.name='OnCloseTab';
ttt();
}

Why is that and how can I store something in the function object?

A function cannot really store values I would say, there is no "this" context in a function, unless it is part of an object, but then "this" will reference the object and not the function. If you are not within an object, you probably still are (script context can also be "this").

If you want to create static members (of objects), you have to attach your member to the prototype of the object / function and create an instance to be able to access the static member with "this..".

Some scripting foo here, maybe it helps to get the idea.. (it can be tricky, no question! o).


this.superStatic = "super";

function myClass( myMemberValue ) {
    this.myMember = myMemberValue;
	WSH.Echo( "this.myMember = " + this.myMember );
	WSH.Echo( "this.myStatic = " + this.myStatic );
	WSH.Echo( "this.superStatic = " + this.superStatic );
}

// has "this" context of parent (script), prints undefined members yet,
// but already knows superStatic member of parent context (current this)
myClass();

WSH.Echo( "----------" );
myClass.prototype.myStatic = "static";
WSH.Echo( "myClass.myStatic = " + myClass.myStatic ); // undefined
WSH.Echo( "myClass.prototype.myStatic = " + myClass.prototype.myStatic ); // static

WSH.Echo( "----------" );
var myInstance1 = new myClass( "foo" );
var myInstance2 = new myClass( "bar" );

WSH.Echo( "----------" );
WSH.Echo( "myInstance1.myMember    = " + myInstance1.myMember );    // "foo"
WSH.Echo( "myInstance1.myStatic    = " + myInstance1.myStatic );    // "static"
WSH.Echo( "myInstance1.superStatic = " + myInstance1.superStatic ); // undefined
WSH.Echo( "myInstance2.myMember    = " + myInstance2.myMember );    // "bar"
WSH.Echo( "myInstance2.myStatic    = " + myInstance2.myStatic );    // "static"
WSH.Echo( "myInstance2.superStatic = " + myInstance2.superStatic ); // undefined

WSH.Echo( "----------" );
myClass.prototype.myStatic = "static - new";
this.superStatic = "super - new";

WSH.Echo( "myInstance1.myMember    = " + myInstance1.myMember );    // "foo"
WSH.Echo( "myInstance1.myStatic    = " + myInstance1.myStatic );    // "static - new"
WSH.Echo( "myInstance1.superStatic = " + myInstance1.superStatic ); // undefined
WSH.Echo( "myInstance2.myMember    = " + myInstance2.myMember );    // "bar"
WSH.Echo( "myInstance2.myStatic    = " + myInstance2.myStatic );    // "static - new"
WSH.Echo( "myInstance2.superStatic = " + myInstance2.superStatic ); // undefined

---------- cscript.exe ----------
this.myMember = undefined
this.myStatic = undefined
this.superStatic = super
----------
myClass.myStatic = undefined
myClass.prototype.myStatic = static
----------
this.myMember = foo
this.myStatic = static
this.superStatic = undefined
this.myMember = bar
this.myStatic = static
this.superStatic = undefined
----------
myInstance1.myMember    = foo
myInstance1.myStatic    = static
myInstance1.superStatic = undefined
myInstance2.myMember    = bar
myInstance2.myStatic    = static
myInstance2.superStatic = undefined
----------
myInstance1.myMember    = foo
myInstance1.myStatic    = static - new
myInstance1.superStatic = undefined
myInstance2.myMember    = bar
myInstance2.myStatic    = static - new
myInstance2.superStatic = undefined

Output completed (0 sec consumed) - Normal Termination
1 Like

Thanks! I thought functions were objects (and that's what your config script and google about JS led me to believe :)) !
For now I'll just store that data in the script vars as that's less tricky

You can create objects from functions, using the "new" statement, but a function is not necessarily an object, well it kind of is, but depends what you want to do (I think). o)

If you are in the script root context you can use "this.myCache" or something to store things on a global level in that script context. You can also re-assign / save the global script context in a variable and use that later from anywhere in the script (using a closure).

//we could omit the "var" here, since we are at script root scope,
//where this variable would be declared anyway, if we omit the var
//statement and assign a value to something yet undeclared 
var gThis = this; // save script root context into "globalThis" gThis

gThis.myCache = {"abc":0, "def":10, "ghi":100};

var isInCache = function( cacheItem ) {
    return (typeof gThis.myCache[cacheItem]) !== "undefined";
}

WSH.Echo( "isInCache: " + isInCache("abc") ); //true
WSH.Echo( "isInCache: " + isInCache("xyz") ); //false

I just want to attach some data to this object :slight_smile:

You can attach any property to any object anywhere, like this:

var myString = "foo";

myString.myProperty = "myown";

If you want all String objects to have the static member, use the prototype approach I demonstrated.