I'm currently creating a project in which every visible element, is represented by javascript object.
I need a method within this object, which will let me destroy it.
There's an example of that object :
var example = function(some_args){
var self = this;
var references = {}; //this holds references to inputs within given view
this.createView = function(){
//here I`m doing "stuff" like filling innerHTML of container
//creating event delegate, etc.
}
this.destroy = function(){
self.elements["box"].parentNode.removeChild(self.elements["box"]); //box is a reference to container element
self.elements = null;
delete self;
}
Now, my question is : am I doing everythig what I have to in order to COMPLETLY destroy this object?
I`m not holding any other references to objects or elements.
EDIT:
I see that some of You do not undestand my question.
Barmar got it right, for which I am gratefull :).
I`m aware of GC, it is just easier to write "I am destroying object" than "I am removing last reference to object, so GC could take care of it" :)
To be specific. Considering that I am removing last reference to object, inside function which is part of this object - is there anything else I should take care of? Or my code is completly fine, and object will be considered as garbage?
You don't handle lifetime of an object in JS explicitly.
So for the given question:
am I doing everythig what I have to in order to COMPLETLY destroy this object?
the only answer is:
You cannot do that, since an object in JS can only be destroyed by a GC, which you cannot interact with. When an object is reachable - then it's alive. When it's not - then it's a "Schroedinger's object".
Javascript has a garbage collector, so you don't need to destroy the object. Also you can't
Related
Attempting to assign a scope object to a JavaScript variable to do minor manipulation before sending to my API. However, any changes made to the JavaScript variable change the scope object.
var recruitingCallListOutput = $scope.RecrutingCallingList.Recruit;
// manipulation of recruitingCallListOutput
The manipulation actually still updates the scope object which is not desired. Feel I am not understanding something in AngularJS correctly. Is there a way to grab the data and detach it from the scope?
In your example, recruitingCallListOutput is a reference to $scope.RecrutingCallingList.Recruit (see https://codeburst.io/explaining-value-vs-reference-in-javascript-647a975e12a0 for more detail.) You will want to make a copy of $scope.RecrutingCallingList.Recruit.
If Recruit is a shallow object, meaning no nested objects (property values are primitives only), you can simply do
var recruitingCallListOutput = Object.assign({}, $scope.RecrutingCallingList.Recruit);
If you have nested objects/arrays as property values, you'll need to deep copy. It's been a while since I have been in the angular world, but
var recruitingCallListOutput = angular.copy($scope.RecrutingCallingList.Recruit)
you could actually use angular.copy in both examples.
This is nothing to do with AngularJS. It's Javascript, and it's expected behaviour.
For example, if you open the browser console (F12->Console) right now and run this:
var foo = {x:1};
var copy=foo;
copy.x=2;
console.log(foo.x);
you will see {x:2} printed out.
This is the same behaviour you would expected for any object reference in Javascript, C#, Java, etc. Because you are making a reference and not a copy, any changes to the reference are actually changes to the original.
The simplest way to solve this problem in your case is to copy the values you are interested in from the item in question into a totally separate object and modify that copy.
e.g.
var recruitingCallListOutput = {
name: $scope.RecrutingCallingList.Recruit.name,
age:$scope.RecrutingCallingList.Recruit.age,
modifiedSomething: $scope.RecrutingCallingList.Recruit.something + 42 //or whatever modifications you need to make
...and so on.
};
There are ways to "clone" an object in Javascript but unless your object is really really complex I would be careful. And consider if you really need all of the properties of the original object anyway, perhaps you only need to send some of them to your backend.
I am using google's 3 Snapshot method to find memory leaks on the page.
Page is running on Knockout.js and Jquery Mobile UI.
I have already narrowed down to one of memory leaking divs. Between each snapshot I am running this script to clear the memory leaking object.
$('.paddedContentContainer').children().each(function(index,item){
console.log(item);
$(item).off();
ko.cleanNode($(item));
$(item).remove();
item = null;
});
.paddedContentContainer is parent of leaking object.
Now the interesting part is that I can still see object in retained object tree. In screenshot below you can see I am filtering on objects in Snapshot 3 that are retained from Snapshots 1 and 2, and by text it's visible that $0 from console in same object that is on the screen (Event Sales Order & ....).
I am assuming that .off(); and .remove(); isin't enough for object to be collected.
How to destroy all references to this object for good?
Have you looked at this post: How to destroy a DOM element with jQuery??
Luke's response seems interesting:
If you want to completely destroy the target, you have a couple of
options. First you can remove the object from the DOM as described
above...
console.log($target); // jQuery object $target.remove(); //
remove target from the DOM console.log($target); // $target still
exists Option 1 - Then replace target with an empty jQuery object
(jQuery 1.4+)
$target = $(); console.log($target); // empty jQuery object Option 2
- Or delete the property entirely (will cause an error if you reference it elsewhere)
delete $target; console.log($target); // error: $target is not
defined
Maybe you should to delete $(item) in the end.
.remove() just removes the element from the DOM, if anything is still referencing it (in your code) it will not be Garbage Collected.
Edit
Yes the .remove() is the correct way of detaching/removing it from the DOM, but it is still held in memory because other things are referencing it (knockout's internals in this example).
One way, and the way I do it, is to keep a collection of all the high-level DOM elements that I create in my controls, then have a destroy function that loops these and calls .remove() on them and assigns them to null
E.g (Note this is held within each control object (no leaky global stuff):
var elements =
{
'table' : $('#some_table'),
'button' : $('#some_button')
};
function destroy()
{
for(var key in elements)
{
elements[key].remove();
elements[key] = null;
}
}
You may be able to take this approach with knockout.
Adding an answer for those who will be satisfied with knockout.js reference removal only.
This removed <div> at hand from object tree.
$('.paddedContentContainer').children().each(function(index,item){
$(item).off();
ko.removeNode(item);
$(item).remove();
item = null;
});
In Actionscript I can do
var thing:MovieClip = new MovieClip ();
thing.somevar = 1;
and the thing object would have a variable called somevar.
Can I do the same in Javascript if I created an element using createElement?
Yes, you'd be creating a custom/unsupported attribute for the HTML element that you can read back. Most people will say that it's not good practice but it does work on all browsers*.
Be careful though to avoid circular references. IE cannot free the memory used by objects with circular references if one of the object is an HTML element. This will result in memory leak on IE. Though other browsers can handle it well enough.
* At least all browsers I've ever tried.
Do you mean this?
var a = document.createElement("input");
alert(a.localName); // gets "input"
In this link: http://css-tricks.com/snippets/jquery/jquery-plugin-template/ it has a line of code that says
// Add a reverse reference to the DOM object
base.$el.data("yourPluginName", base);
what does the "reverse reference to the DOM object" mean?
Assuming that you know the jQuery data function:
It's storing a reference to the instance of the class in the data cache of jQuery, meaning that the stored instance can be used to access the initial base object if it in the current context is not available.
This way, the class instance can be used later. However, the use of the prototype keyword upon the initial class that the instance were created from will modify the instance.
EDIT:
Ooops, it seems that Anurag is right, and I was giving wrong information.
Sorry, the information I gave in initial answer was not completely correct. I've updated the answer, so it now tells the truth.
In the comments you're asking:
so you mean its storing the current state of "base" in the data cache but if we make changes to "base" later on then the one in the data wont be affected? so if for some reason we needed to get the original one again we can do data('yourPluginName') to retrieve it? can you give me an example of when this would be helpful?
It seems that none of the statements are correct.
As I did obviously not remember adequately, the thing stored in data is only a reference to the object:
var obj = {};
obj.hello = "Hello";
$("#someElement").data("object", obj);
obj.world = " world.";
alert(
obj.hello +
$("#someElement").data("object").world
); // alerts "Hello world."
BTW, JavaScript variables with names like this base-thing (but, more often seen as that or similar) are typically used to represent the current context, accessed through the this keyword, which on many occasions is more easy to store in another variable due to scoping/context changes, that will make the current context and therefore this, change.
Also due to issues with context, the stored value in data could be used to access the specific object instance from another context (that is, when this represents something else), instead of the version of the base object that was continually used after a copy of it was stored.
I hope this answered you questions :D
The technique and the problem it solves is general and not specific to jQuery plugins. There may be cases where a Javascript object corresponds to a DOM element, and wraps logic specific to that DOM element. This object might be interested in listening to events such as clicks that happen within that DOM element. The information we get in those callbacks is the element that triggered it, and not the associated object. You could use jQuery's data API or any type of map in general to retrieve the corresponding object, and do something with it.
I have a JS object I use to store DOM info for easy reference in an elaborate GUI.
It starts like this:
var dom = {
m:{
old:{},
page:{x:0,y:0},
view:{x:0,y:0},
update:function(){
this.old = this;
this.page.x = $(window).width();
this.page.y = $(window).height();
this.view.x = $(document).width();
this.view.y = window.innerHeight || $(window).height();
}
I call the function on window resize:
$(window).resize(function(){dom.m.update()});
The problem is with dom.m.old. I would have thought that by calling it in the dom.m.update() method before the new values for the other properties are assigned, at any point in time dom.m.old would contain a snapshot of the dom.m object as of the last update – but instead, it's always identical to dom.m. I've just got a pointless recursion method.
Why isn't this working? How can I get a static snapshot of the object that won't update without being specifically told to?
Comments explaining how I shouldn't even want to be doing anything remotely like this in the first place are very welcome :)
this is a reference to an object. You're not storing a copy of an object. You're storing a reference to that object. If you want a copy you'll need to copy the properties by hand. The easy way is to use $.extend():
this.old = $.extend({}, this);
OK right, the terminology is 'deep' copy. I would've thought it was the other way round (just get an impression rather than the object itself). So anyway Cletus is right but the syntax is:
this.old = $.extend(true,{},this)
And apparently 'snapshot' is 'clone' in developer lingo.