Variable is "undefined" when used in a different method? - javascript

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

Related

Using Prototype's Properties before Function's Prototype is Set

I would like to assign a property to a function's prototype and use that property prior to setting the prototype as the function's prototype (hard to explain). If I was doing this in Java, I would just create a public static final variable on the base class. For instance...
function Foo(a, b) {
this.a = a;
this.b = b;
}
function Bar() {
this.prototype.A = 100;
this.prototype.B = 250;
Foo.call(this, this.prototype.A, this.prototype.B);
}
Bar.prototype = Object.create(Foo); // Bar.A and Bar.B are now undefined, not what I
// want to happen.
Potential implementation #1...
function Foo(a, b) {
this.a = a;
this.b = b;
}
var tempA = 100;
var tempB = 250;
function Bar() {
Foo.call(this, tempA, tempB);
}
Bar.prototype = Object.create(Foo);
Bar.prototype.A = tempA;
Bar.prototype.B = tempB;
Potential implementation #2...
function Foo(a, b) {
this.a = a;
this.b = b;
}
var barPrototype = Object.create(Foo);
barPrototype.A = 100;
barPrototype.B = 250;
function Bar() {
Foo.call(this, barPrototype.A, barPrototype.B);
}
Bar.prototype = barPrototype;
Does anyone have a preference as to which implementation is better? Or is there a more elegant way (no temp variables) to do this?
Do you just want to extend Foo's prototype and add additional attributes to it? For that you could use something like this:
function Bar() {
new Foo.call(this, this.A, this.B); // It's a constructor, should use new
}
var proto = Object.create(Foo.prototype);
proto.A = 100;
proto.B = 250;
Bar.prototype = proto;
However, if you wanted to extend this further, then you're really looking for a mixin method, which will allow you to merge two objects together. If you're already using jQuery (note: definitely not advocating just for this purpose), you could use the $.extend() method:
Bar.prototype = $.extend({}, Foo.prototype, {
A: 100,
B: 250
});
If you're not using jQuery, it shouldn't be hard to find a similar method elsewhere (e.g. Underscore has one too)
If you want to have a shared variable, to be available to both Foo and Bar, then you could alternatively wrap their definitions in an Immediately-Invoking Function Expression (IIFE) and define your A and B private variables within this function:
(function() {
var A = 100,
B = 250;
function Foo() { ... }
function Bar() {
Foo.call(this, A, B);
}
})();
This would be more appropriate if A and B are more global constants, and not intrinsically linked to Bar.

Javascript garbage collector on internally referenced object

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.

javascript pass parameter values to same named outer scope variables

var a,b,c;
function abc(a,b,c){
console.log("a is"+ a + ", b is"+ b + ", c is"+ c);
}
a; // undefined
b; // undefined
c; // undefined
I will be passing through strings a,b,c, but would like to also be able to access them once they are passed through the function.
So if I call abc("d","e","f"), I'd like that function to run using those three strings, but afterwards, outside of its own scope, I'd also like to be able to use a="d", b="e", and f="f".
Could someone explain how this is done? I think that even though they are declared outside of the function, the fact that it's the same name is throwing me off.
I remember something in PHP about adding & before the parameter...
Thanks!
I'm not sure what you're asking here, but it works just out of the box like you want it.
Since ECMAscript has function scope, the variables a, b and c will get locally resolved within the function context of abc(). The outer declarations of those
variable names (lets call them free variables), will never get accessed because the lookup process will find those names first within its *own context, resolve them and stop there.
If you just want to set those free variables which are part of a parent context, you probably should rename your formal parameters for convenience and then pass over the values
function abc(some, other, name) {
a = some;
b = other;
c = name;
}
Hopefully that parent scope where a, b and c are declared is not the global scope. That is very correctly still considered bad practice and karma, for a couple of reasons.
Best practice would be to give the inner variables different names, e.g. by prefixing them with 'inner' or the initials of the function name. Not only can you then simply assign the values to the outer variables with a simple a = innerA, but it also makes your code more readable.
You can't use the variables in the outer scope if they're masked by function parameters with the same name.
You could, if they were named properties of a variable that is in the outer scope. In browsers, global variables are actually just properties of the window variable:
var myobj = {};
function abc(a, b, c) {
myobj.a = a;
myobj.b = b;
myobj.c = c;
}
// you can now use those values
Firstly, I think you mean:
var a, b, c;
function abc(_a, _b, _c) {
a = _a;
b = _b;
c = _c;
}
abc(1, 2, 3);
console.log("a is"+ a + ", b is"+ b + ", c is"+ c); // 1, 2, 3
Given that said, I think this approach is not a good practise. Please organise them within a closure or a namespace. For example, here is an acceptable design pattern :
(function(g) {
var _SomeClass = function(a, b, c) {
this.a = a;
this.b = b;
this.c = c;
}
_SomeClass.prototype = {
printValues: function() {
console.log(this.a, this.b, this.c);
},
doSomething: function() {
// do something here
},
_privateMethod: function() {
// should not be called from outside the closure
}
}
g.SomeClass = _SomeClass;
})(window);
var myClass = new SomeClass(1, 2, 3);
myClass.printValues();

How to add functions to prototype of inner function in the global scope in JavaScript?

function A() {
this.B = function() {
var bla;
};
}
A.B.prototype.foo = function() {console.log("Do whatever");};
I get this:
TypeError: Cannot read property 'prototype' of undefined
How to add a function to the prototype of B in this case?
There are a couple of mistakes in our code... here is how:
function A() {
this.B = function() {
var blah;
};
}
a = new A();
a.B.prototype.foo = function() {console.log("Do whatever")};
Your first issue was doing:
this.B() = function...
That's not valid code, since you were calling method B and assing it a function, you had to reference the attribute.
Your other mistake, was not instantiating an "A" object, the function by itself can't be used as an object, it can only be called. That's why when you had:
A.B.prototype
You recieved that error message.
I hope that clears things up a bit for you, let me know if you have more doubts.
B is a property of A, and can only be accessed from instances of A.
var aObj = new A;
aObj.B();
You cannot access A.B without using an instance of A.
You could access aObj.B.prototype, and add methods to that.
aObj.B.prototype.foo = function(){
return 'test';
};
var bar = new aObj.B;
console.log(bar.foo()); // 'test'
var bObj = new A;
var foobar = new bObj.B;
console.log(foobar.foo()); // `foo` is undefined
You need to make the inner function accessible by adding it to the outer prototype, then you can add functions to the inner object by using Outer.prototype.Inner.prototype without the immediate need for an instance of the outer object.
function A() {this.a="a";}
A.prototype.B = function() {this.b="b";}
A.prototype.B.prototype.foo = function() {console.log("b is:"+this.b);}
var a=new A();
var b=new a.B();
b.foo();

Nesting of classes and this value in JavaScript

Can I write nested classes in Javascript?
function A()
{
this.a;
this.B = function()
{
this.ab ;
this.C = function()
{
this.ab = 0;
}
}
}
If the above code is correct,then
1.How do I declare an object of type B
2.Whose property is ab.A() 's or B() 's?.
3.Inside B() where does the 'this' points to.To A() Or to B()?
In your example, the "classes" will be instance-specific. Are you sure you want that? You might be looking for something more along the lines of:
function A() {
// ...
}
A.B = function() {
// ...
};
var one = new A();
var two = new A.B();
Although the "nested" classes won't be able to access "private members" because JavaScript doesn't have those in the first place.
As for your example:
You would create an instance of A, say new A(), and access B, say new new A().B()1, or replacing new A() with a variable.
Neither, it's an empty statement for now... but it would be a property of the B instance.
To an instance of B (unless Function.call or Function.apply is used).
1 Yes, it works!
Abstract:
Calling to function without using new operator means that this will be refer to object in which that function was created.
For global variables this object is window object.
Calling using new - function behave as constructor like in classes and this refers to this instance which will been created
1.How do I declare an object of type B
First way( as a curiosity ) - by calling to A without using new operator this will be refer to windowobject and B method and all other what was declared with this leaks to global scope because A == window.A => true
A();
var b = new B; // means => new window.B //parentheses can be ommited if you invoking without arguments
alert( ab ) // alerts 'inside A' -> value from code presented below
or from instance of A:
new new A().B // means => new ( new A ).B
Be careful.
2.Whose property is ab.A() 's or B() 's?.
As above, it depends of how we'll accessing to it:
function A()
{
this.ab = "inside A";
this.B = function()
{
this.ab = "inside B";
this.c = function()
{
this.ab = "inside C";
}
}
};
Check this out
var a = new A;
a.ab // "inside A"
a.B(); // in B now 'this' refers to 'a', 'a.ab' will be replaced to 'ab' from inside 'B'
a.ab // "inside B"
but
var a = new A;
a.ab // "inside A"
var b = new a.B;
a.ab // "inside A"
b.ab // "inside B"
// and now
b.c()
b.ab // "inside C" and so on:)
3.Inside B() where does the 'this' points to.To A() Or to B()?
As above:)
It's very unorthodox, but there's nothing stopping you from nesting constructor functions in JavaScript.
From your example, you can access the B function from an instance of A:
var someA = new A();
var someB = new someA.B();
To answer your other question:
this.B = function() {
this.ab = 0;
this.c = function() {
this.ab++;
}
}
What this refers to inside of B depends on how B is invoked. If you call B as a constructor, with the new keyword, this will be a new object inheriting from B's prototype.
If you call B without new, it will be treated as a method, and this will be the instance of A on which the method was called.
And so on with C. If C is called with new, this inside of C will be a new object inheriting from C's prototype. Or C can be a method of B, which makes a lot more sense. Is something like this what you're wanting:
function A() {
this.a;
this.B = function() {
this.ab = 0;
this.c = function() {
this.ab++;
}
}
}
var someA = new A();
var someB = new someA.B();
console.log(someB.ab); //0
someB.c();
console.log(someB.ab); //1
DEMO
Finally, note that, though nesting constructors like this isn't too common, there's nothing stopping you from adding to B's prototype just like you would any other constructor
function A() {
this.a;
this.B = function() {
this.ab = 0;
this.c = function() {
this.ab++;
}
}
this.B.prototype.foo = function() { alert("Bar " + this.ab) };
}
var someA = new A();
var someB = new someA.B();
console.log(someB.ab);
someB.c();
console.log(someB.ab);
someB.foo(); //Bar 1
Updated Demo

Categories