I've been reading many SO questions about javascript garbage collection but this is just slightly confusing me. Take a look at my example
var valueObject= (function(){
function valueObject(){
this.Text = 'hello';
}
return valueObject;
})();
var referenceObject = (function(){
function referenceObject (refObject){
this.Reference = refObject;
}
return referenceObject ;
})();
var globalClass = (function(){
function globalClass(){
}
globalClass.prototype.load() {
this.A = new valueObject();
this.B = new referenceObject(this.A);
}
globalClass.prototype.destroy() {
this.A = null;
this.B = null;
}
return globalClass;
})();
var Test = new globalClass();
Test.load();
Test.destroy();
Now once the Test object destroy has been called, will the valueObject and referenceObject be marked for collection? Because this.A = null will remove the reference to the valueObject, but it still has a reference inside this.B. But if this.B = null is called, the reference to this.B is removed, but the B object will still be there with a reference to A?
Not sure if that makes any sense, it's a little confusing to me. Thanks.
Firstly, it is convention to use names starting with a capital letter for constructors only, your code has that convention backward, mostly.
Now once the Test object destroy has been called, will the valueObject and referenceObject be marked for collection?
Dunno about "marked", but available, yes.
Because this.A = null will remove the reference to the valueObject
Yes
but it still has a reference inside this.B
No, it doesn't.
Looking at the code (and fixing errors):
globalClass.prototype.load = function () {
this.A = new valueObject();
this.B = new referenceObject(this.A);
}
First, the load method adds an A property with a value that is returned by the call to valueObject, which is just a plain object.
It then adds a B property that references another object with a Reference property that references the same object as A.
But if this.B = null is called, the reference to this.B is removed, but the B object will still be there with a reference to A?
Yes, but since there are now no references to the object formerly referenced by B, and it's the only object that referenced the object formerly referenced by A, they are both available for garbage collection.
Related
This code works fine, although what I'm interested in knowing is, if there's a way that works better and is which I prefer better, which it seem to not be working. Is it possible to do it that way, check the second code example in order to comprehend, what I have in mind when I say "preferred way".
code 1
function a(y){this.b=y;};
var ax = new a("oka");
alert(ax.b);
code 2 (preferred way but does not work)
function a(){this.b = alert(y);this.y = y;}
var ax = new a();
ax.y="okay";
ax.b;
Your use of this is mostly fine, but the problem is that this line:
this.b = alert(y);
...calls alert and assigns its return value to b. If you wanted b to be a function, you'd do:
this.b = function() {
alert(this.y); // Note `this`
};
...so:
function a() {
this.b = function() {
alert(this.y);
};
}
var ax = new a();
ax.y = "okay";
ax.b(); // Note the ()
Side note: The overwhelming convention in JavaScript is to give constructor functions (functions you call via new) names starting with a capital letter. So A rather than a, for instance.
If you want to assign a function to the this.b property, you can do it like so:
// Declare the a variable.
var a = {};
// Set the a.b property.
a.b = function(){alert('hi');}
// Call the function set on a.b.
a.b();
I am extremely new to javascript so apologize for questions that may be trivial ?
var foo = function () {
a = "10";
this.b = "20";
};
foo.c = "30";
console.log(foo.a); // undefined
console.log(foo.c); // prints 30.
var foo1 = new foo();
console.log(foo1.b) // prints 20
How to access var "a" ? Is it even possible ?
Actually, as long as you don't prefix the variable declaration with var it will be global:
var foo = function () {
a = "10";
this.b = "20";
};
foo();
console.log(a); // is 10
Compared to:
var foo = function () {
var a = "10"; // private scope
this.b = "20";
};
foo();
console.log(a); // is undefined
Using global variables:
var a = 10;
var foo = function() {
a = 15;
this.b = 20;
};
console.log(a); // equals 10
foo();
console.log(a); // equals 15
If you wanted to actually access the variable a within the function, much like your example:
var foo = function() {
a = 10; // private member
};
There is no way to access that private member.
Turns out when you declare a variable in this way, you have created a global variable. You can access it with console.log(a); and it will return 10. However if you use var a = 10; inside the function, you will not be able to access this member.
What you can do is return an object in your constructor that defines public members:
function Foo() {
var a = '10';
function getA() {
return a;
}
return {
'a': a,
'b': 20,
'getA': getA
};
}
var foo = new Foo();
console.log(foo.a) // 10
console.log(foo.b); // 20
console.log(foo.getA()); // 10
The code
console.log(foo.a);
console.log(foo.c);
implies that you believe that a would be set as the equivalent of foo.a = "10", that is setting a static field of the "class" foo. This is not the case in JavaScript.
a = "10";
This sets the global variable a to the value "10", creating a global variable slot if necessary. This type of global assignment should be avoided and is caught by tools like JSLint.
this.b = "20";
This sets the field of the object passed as the this parameter of the function to "20", creating the field slot if necessary. Note that if you call foo directly, e.g. foo(), without new, the global scope is passed as this and this.b will also create a global variable. This type of error can be caught by strict mode. If you execute in strict mode, undefined is passed in as the this parameter and this will throw an exception.
var foo1 = new foo();
This creates a new, empty, object with the __proto__ property set to the value of the prototype property of foo and then calls foo passing the new object as the this parameter. All fields of __proto__ appear as the default values of fields of the object. This leads to the convention of adding methods to the prototype object of the constructor function and initializing fields in the constructor function. Inheritance can be simulated by constructing an object with the ancestor prototype object as its __proto__ value and assigning it to the functions prototype property of the constructor function. The constructor function would also call the ancestor constructor function (without new), passing its this as the constructor function's this parameter (using apply or call). This is all a bit awkward so ECMAScript 6 standardized this into a class construct which roughly translates to what I described.
I know you can have one javascript instantiated object inherit the prototype of another constructor with constructer.prototype.__proto__ = otherConstructer.prototype, but can you use the call method like this to do the same thing?:
function constructor () {
otherConstructor.call(this);
}
No, the prototype can't be replaced except by referencing the object itself and directly replacing it with the __proto__ property, which doesn't exist in all implementations. Look at this sample code:
function B() {
this.someValue = "BBB";
}
B.prototype.testfunc = function() {
console.log("Called from B: someValue =" + this.someValue);
}
function A() {
this.someValue = "AAA";
return B.call(this);
}
A.prototype.testfunc = function() {
console.log("Called from A: someValue =" + this.someValue);
}
var test = new A();
test.testfunc();
// Will output "Called from A: someValue =BBB"
As you can see, the B constructor is correctly called and the object setup is from B and not A, but nevertheless the object's prototype is still from A. You can, of course, replace individual functions:
test.testfunc = B.prototype.testfunc;
test.testfunc();
// Will output "Called from A: someValue =BBB"
If you want a great explanation of why this is so, check out the accepted answer to this question.
Edit: There is no association with B.prototype when an A object is created. If you changed the code so that A.prototype.testfunc is not defined, then even though the A constructor calls B, nevertheless calling test.testfunc() will result in an undefined exception.
I have this code for the setup of an object:
myObj.prototype.__init = function(a, b, c){
this.a = a;
this.b = b;
this.c = c;
}
And then in another function I want to use the a I setup in the __init method:
myObj.prototype.myFunc = function(){
var data = parse(a);
//...
}
The problem is that a is undefined. I also tried this.a and it results undefined too. The funny thing is that a console.log(myO) after doing a var myO = new myObj(); and myO.__init(myA, myB, myC); prints the object with the field a initialized. How do I access then a inside that function of my object?
Thanks
EDIT: This is the call to myFunc:
someVar = new tccHandler.myObj();
someVar.__init(myA, myB, myC);
someVar.myFunc();
I suspect it should be parse(this.a).
Remember that properties of this are not in the lookup-chain for identifiers [read: variables] by default; only lexical variables and properties of "the global object" (i.e. window) are.
a is a variable in the function __init (as a function parameter), where the object it names is assigned to the property this.a, but a is not a variable of the function myFunc. Each function introduces it's own lexical scope.
Happy coding!
In normal javascript, you would do:
myObj = function(a,b,c) {
this.a = a;
this.b = b;
this.c = c;
}
Demo:
> var x = new myObj(1,2,3);
> x.a;
1
I've recently started reading up on OOP javascript and one thing that authors seem to skip over is when an object A has been declared and suddenly I see "A.prototype.constructor =A;
For example,
var A = function(){}; // This is the constructor of "A"
A.prototype.constructor = A;
A.prototype.value = 1;
A.prototype.test = function() { alert(this.value); }
var a = new A(); // create an instance of A
alert(a.value); // => 1
So I run the command in firebug "var A = function(){};"
and then "A.Constructor" Which reveals it's a function. I understand this.
I run the code "A.prototype.constructor = A;" and I thought this changes the A constructor from Function to A.
The constructor property of A has been changed right? Instead when I run "A.constructor" it gives me function () still.
What's the point?
I also see A.constructor.prototype.constructor.prototype.. what is going on?
If A inherit B using A.prototype = new B();, you need to reset the constructor property for the class A using A.prototype.constructor=A;, otherwise instances of A would have a constructor of B.
In your case, A.prototype.constructor === A will return true, so A.prototype.constructor = A did nothing.
You can quickly test out that that additional assignment does absolutely nothing:
var A = function() {};
A.prototype.constructor === A; // true -- why assign then?
Resetting the constructor property only makes sense if you've assigned a new prototype object to the class, overwriting the original constructor:
var A = function() {};
A.prototype = protoObject; // some object with members that you'd like to inherit
A.prototype.constructor = A; // reset constructor
In your case, the author might be blindly doing this as good practice, even in cases where it's not necessary.
This code if often use in JS classic inheritance pattern (the code is from JavaScript Patterns by Stoyan Stefanov):
function inherit(C, P) {
var F = function () {};
F.prototype = P.prototype;
C.prototype = new F();
C.uber = P.prototype;
C.prototype.constructor = C;
}
to assign right constructor to the child class.
In your case it did nothing, since A.prototype.constructor === A before assignment.
You might want to see my answer to similar question:
https://stackoverflow.com/a/19616652/207661
TL;DR: constructor is not an own property of an instance. So to make things look consistent JavaScript interpreter needs to set prototype.constructor to function itself. This feature can be used in functions that operates generically on many different types of objects.
According to MDN, All objects inherit a constructor property from their prototype:
Example 1:
var o = {};
o.constructor === Object; // true
..
Example2:
function Tree() {
}
var theTree = new Tree();
console.log(theTree.constructor === Tree ); // true
At runtime, it does not make any difference based on the value of the constructor property.
However, as the constructor property returns a reference to the Object function that created the instance's prototype, one should reset the constructor property when they assign a new prototype to the Object function.
var Forest = function() {};
Forest.prototype = theTree;
console.log(new Forest().constructor === Tree ); // true
Forest.prototype.constructor = Forest;
console.log(new Forest().constructor === Forest ); // true
https://jsfiddle.net/j1ub9sap/
For details: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor