javascript: How to destory class Object and make calling variable undefined? - javascript

How do I properly destroy a class object of MyClass and make the calling variable myObj = undefined?
var namespace = {};
namespace.instance = {};
function MyClass(name) {
this.name = name;
this.destroy = function() {
delete namespace.instance[name];
}
namespace.instance[name] = this;
}
var myObj = new MyClass('test');
console.log(myObj);
myObj.destroy();
console.log(myObj) // make this undefined;

In JavaScript, you cannot make a variable point to undefined without explicitly assigning undefined to the variable name. After you do
var myObj = new MyClass('test');
the only way to make myObj undefined is to do
myObj = undefined;
afterwards.
Given only a reference to the object (such as in a destroy method), there's no way to break the outer myObj reference to the object; all you can do in destroy is mutate the object, but it'll still remain an object. What you're looking for isn't really possible in JS.

Related

Trying to refresh my knowledge of the Prototype Tree. What is wrong here?

According to http://js4py.readthedocs.org/en/latest/object-tree.html,
All JavaScript objects are part of an inheritance tree. Each object in
the tree has a parent object, which is also called the prototype
object (of the child).
I was playing around to make sure I understand it correctly. Shouldn't the following print "lakdas" since myOtherObj inherits the field x from its parent myObj? Why does it instead log undefined?
var myObj = { x:"lakdas" };
var myOtherObj = { y:"lkjaas" };
myOtherObj.prototype = myObj;
console.log(myOtherObj.x); /* Should print "lakdas", right? */
You can't change an object's prototype by assigning to a prototype property. In many engines you can't change the prototype at all after the object is created. You can set the prototype at object creation time:
var myObj = { x:"lakdas" };
var myOtherObj = Object.create(myObj); // sets prototype
myOtherObj.y = "lkjaas";
console.log(myOtherObj.x); // prints "lakdas"
Functions have a prototype property - when you use a function as a constructor, the object stored in the function's prototype property becomes the prototype of the constructed object:
var myObj = { x:"lakdas" };
function foo() {
this.y = "lkjaas";
}
foo.prototype = myObj;
var myOtherObj = new foo();
console.log(myOtherObj.x); // prints "lakdas"

Understanding this in call and apply

As per definition of call and apply, they execute function on given context.
But, following code returned Object{} for this
function Animal() {
this.name = "Lion";
this.id = 1;
this.getInstance = function() {
return this;
}
}
var myObj2 = {};
var myObj = new Animal();
myObj.getInstance.call(myObj2); //Object {}
When I used self to store the this, then it returned Animal object.
function Animal() {
self = this;
this.name = "Lion";
this.id = 1;
this.getInstance = function() {
return self;
}
}
var myObj2 = {};
var myObj = new Animal();
myObj.getInstance.call(myObj2); //Animal {name: "Lion", id: 1, getInstance: function}
In both the cases, my understanding was it should return myObj2.
What is possible explanation for this?
What is possible explanation for this?
self was set when var myObj = new Animal(); was called, at which point this referred to a new Animal instance.
Calling myObj.getInstance.call(myObj2); doesn't magically change the value of self. It still has the value that was set when new Animal() was executed.
Furthermore, each function has "their own" this and the value of one function's this does not affect the value of another function's this, nor does it have any impact on assignments that happened in the past (self = this; happened before getInstance is called and in a different context).
Here is a hopefully simpler, but equivalent example, which doesn't use this:
function Animal(foo) {
var self = foo;
this.getInstance = function(foo) {
return self;
}
}
var myObj2 = {};
var myObj = new Animal('abc');
myObj.getInstance('xyz'); // returns 'abc'
Both functions, Animal and getInstance have a parameter foo. When Animal is called, self is set to the value of Animal's foo ("abc").
Later we call getInstance with a different for its own foo parameter ("xyz"). However, that does not affect Animal's foo, nor self, since we are only reading the value of self, which is still "abc".
When you use call, youe are telling the function that the parameter passed must work as "this" inside that concrete function, so, when you use call and pass myObj2, this = myObj2 inside getInstance method, what is why you get the empty object.
Within the function declaration for Animal(), this equals the current instance of Animal(). When you assign the value of this to variable self, you're locking in that definition statically, meaning it won't change. It will always return Animal().
When you used call(), you instructed the Animal() function to refer to myObj2 as this - as if Animal() were a method of myObj2. So this equals the context that you passed, which is, in this case, an empty object literal.

Is it possible to get the name of the declaring scope of a variable?

I have a variable at some point of a JavaScript code. Now I would like to get the name of the function (aka scope) where that variable was declared. So for example if that variable is a field of an oject, I would like to get the name of the object's type.
Consider the following code:
function MyClass() {
this.name = "MyName";
this.age = 20;
}
var myVariable = new window.MyClass();
alert(getDeclaringScope(myVariable)) // should alert 'window'
alert(getDeclaringScope(myVariable.name)) // should alert 'MyClass
Is there any way to implement the getDeclaringScope function?
UPDATE
I wanted to use some technic like this to access to access a kind of "static" variable where meta information is stored for knockoutjs observable. A farly simplified example:
var META = {};
META["MyClass"] = {};
META["MyClass"]["MyArray"] = { ElementType: "MyOtherClass" };
function MyClass() {
this.MyArray = ko.observableArray();
}
function MyOtherClass() {
this.name = "a";
}
ko.observableArray.fn.addFromPlainObjects = function(plainItems) {
var elemType = .... here I wanted to get "MyOtherClass" from the META global variable
// create MyOtherClass and map the plain items to it... etc.
}
No.
The object has a reference to its constructor, but the constructor could be referenced from many objects, not just window in this case. It could be accessed directly with a variable (as opposed to a property):
var MyClass = window.MyClass;
var foo = new MyClass();
You can create a back-reference explicitly in your object model, as constructor functions are objects.
window.MyClass.backref = window;
Though this is most likely not what you want. I suspect you have a misunderstanding regarding what the scope of a variable is; a variable scope has nothing to do with object properties. As such, there is no notion of "declaring scope" that represents the object and object property from which a variable reference was retrieved, as you seem to conceptualize it.
You can use instanceof and constructor:
Eg.
myVariable instanceof MyClass; //true
myVariable.constructor;
// returns
function MyClass() {
this.name = "MyName";
this.age = 20;
}
Check: instanceof and constructor

object in prototype is inherited as reference

I want to inherit new object instance using prototype.
Test case:
var MyObj = function() {}
MyObj.prototype.objName = {}
// I want this to be a different object for each instance of MyObj
var o1 = new MyObj (),
o2 = new MyObj ();
o1.objName['a'] = 1;
o2.objName['a'] = 2;
alert(o1.objName['a']) // 2
alert(o1.objName === o2.objName) // true
This means that objects in prototype are not inherited as its copies but instead as its reference.
I know that normally you can do it like this.
var MyObj = function() {
this.objName = {}
}
var o1 = new MyObj(),
o2 = new MyObj();
alert(o1.objName === o2.objName) // false
This works fine, but in my case this is not an option. I really need to define objName outside the MyObj function.
I managed to "solve" the problem with this
MyObj.prototype.objName = function() {
if ( this._objName === undefined ) {
this._objName = {};
}
return this._objName;
}
var o1 = new MyObj(),
o2 = new MyObj();
o1.objName()['a'] = 1;
o2.objName()['a'] = 2;
alert(o1.objName()['a']) // 1
But this is not very pretty and the performance of this code is much worse.
Is there any way to solve this more elegantly ?
This means that objects in prototype are not inherited as its copies but instead as its reference.
Nothing on the prototype is copied - the whole concept of prototypical inheritance is that properties reference the shared properties of the prototype object. So if you want a property to be individual for each instance, you have to explicitly assign it to the object and shadow the prototype property; just as you're doing it with the _objName property in your code.
But this is not very pretty and the performance of this code is much worse.
If you want it pretty, move it to the constructor (or make the constructor look for something like an init method to call if exists, then you can create that init method on the prototype.
To make performance a little better, you can change the getter function to
MyObj.prototype.getObj = function() {
var obj = {};
this.getObj = function(){ return obj; }; // overwrite itself
return obj;
};
though it still has the function call overhead. For even more elegance, you can use a getter property (not supported in old browsers) that removes itself on the first access:
Object.defineProperty(MyObj.prototype, "objName", {
get: function() {
var obj = {};
Object.defineProperty(this, "objName", {
value: obj,
writable: true //?
});
return obj;
},
enumerable: true,
configurable: true
});
Now you can omit the function call parenthesis.
This means that objects in prototype are not inherited as its copies but instead as its reference.
Just to be clear. First of all in JavaScript all objects are passed by reference, not by value. Only primitives are passed by value.
Second, you're not actually "copying" or "passing" anything. When you set a prototype, you're creating a prototype's chain. It means that in your case:
var MyObj = function() {};
MyObj.prototype.objName = {} ;
var o1 = new MyObj ();
var o2 = new MyObj ();
Both o1 and o2 doesn't have any property called objName, and you can simply test it with:
console.log(Object.keys(o1)); // []
When JS see a code like o1.objName, as first thing checks if the object has this property, and if it has, use it. If not, start to looking in the prototype's chain, starting by the prototype of o1, that is MyObj.prototype: it found the properties objName, and returns it. If it didn't find it, then JS will continue to check the prototype of MyObj.prototype, and so on. So, here the point: MyObj.prototype it's an object: and you shared that object between o1 and o2. That's why the instance of objName is the same. It's exactly the same logic of having:
function objName(obj) {
return "objName" in obj ? obj.objName : O.objName;
}
var O = { objName: [] };
var foo = {};
var bar = {};
objName(foo).push(0);
objName(bar).push(1);
So, you can't put in prototype any object that is not meant to be shared across the objects creates using that prototype. I would say that shared states like that is also a bad practice that should be avoided, that's why in general prototype shouldn't have such property.
It's still not clear to me why you can't modify the constructor, but the point is: when you create the instance of your object, you have to "setup" it. Usually, calling the constructor, but any function is fine. This is made also when you want to support inheritance, and calling the "super" constructor to initialize your object.

Whats the difference declaring variables with and without prototypes

Whats the difference between (via prototypes)
var Todo = {};
Todo.prototype.name = "...";
Todo.prototype.hello = function() { ... }
Vs (variables & functions "outside" object)
var Todo = {}
Todo.name = "..."
Todo.hello = function() { ... }
Or even the below : variables & functions in object
var Todo = {
name: "...",
hello = function() { ... }
}
Think it like
A property or a function declared with prototype is an instance member of Todo.
A property or a function declared without prototype is a static member of Todo.
The first one doesn't make sense as you are dealing with an object instance (({}) instanceof Object === true), it won't have a prototype property (Object does).
You may be inquiring about the difference between these two patterns...
var ObjA = function() {
this.method = function() {};
};
var ObjB = function() {};
ObjB.prototype.method = function() {};
jsFiddle.
The former will use more memory when instantiated - each object has their own method. The latter won't each have their own method, the method lives on the prototype object, which is the next in command on the prototype chain when its attempted to be accessed on the parent.
Todo.prototype is also an object, so the difference is if you declare property with prototype, then every object who created from this prototype will have the property, otherwise, the property is only for Todo the object self.
A significant difference between method #1 and #2 (which is almost identical to example #3) is on new keyword that you need to use if you extend your function via prototype, e.g.
var Todo1 = function() {};
Todo1.prototype.name = "Foobar";
var Todo2 = {name: "Foobar" }
var a = Todo1;
console.log(a.name); // no property retrieved
var b = Todo2;
console.log(b.name); // Foobar
var c = new Todo1;
console.log(c.name); // Foobar

Categories

Resources