destroy a function in javascript (jquery)
Asked Answered
F

4

5

Is there anyone who knows how to destroy a javascript (jquery) function? I'm using jquery "selectable" and a function call "edit" is fired on selectable "stop" event.

Inside this "edit" function I have nested switch functions with a lot of "click" events and I have many functions within each "click" event. My problem is, every time I fire the "selectable" functions and events inside the function "edit" is fired again but the previous functions and events still exist. What i do now is to unbind every event in the function "edit" on selectable "start" even.

Is this a memory leak problem? and is there a way to "destroy" functions in javascript? i have tried to declare the function to null when the function ends but this does not work. functions and events inside it still exist.

anyone have a clue?

demo page here --> http://dreamerscorp.com/test/test01/javascript_destory_test.html

edit 2009/10/31 :) thanks a lot for your helps, your comments are very useful to me, thanks again!!!

Flamen answered 30/10, 2009 at 4:11 Comment(1)
Yes, another +1 for the demo page.Malathion
M
5

Basically you need to remove all references to those functions so that the JavaScript garbage collector can collect them. If they are bound, you need to unbind them. If there are other variables in there that point to them, they need to be set to null.

It might help if you posted some code; then we can give a better answer.

...EDIT:

What's happening here is, you're creating a closure that will outlive the containing function:

    function edit(){
      $('.edit').click(function(){
        //...
        function _edit(boxTitle,selectedItemAmount){
          //...
          $('#box .yes').click(function(){
            alert(boxTitle + ' for ' + selectedItemAmount + ' selected item');
            $('#msg').hide(); // hide msg box when yes btn is clicked
          });
        }
        //...
        $('#box .no').click(function(){
          $('#msg').hide();
        });
      });

In other words, inside a function, you're saying, "Attach this function to a DOM object," and you're doing it inline. JavaScript captures variables from outer contexts and keeps them alive while the reference to the inner context is alive.

What you need to do is to define the functions somewhere not inline and then use them:

    function boxClickYes(e) {
      alert(e.data.boxTitle + ' for ' + e.data.selectedItemAmount +
        ' selected item');
      $('#msg').hide(); // hide msg box when yes btn is clicked
    }
    function boxClickNo(e) {
      $('#msg').hide();
    }
    function edit(){
      $('.edit').click(function(){
        //...
        function _edit(boxTitle,selectedItemAmount){
          //...
          $('#box .yes').bind("click", {boxTitle: boxTitle,
            selectedItemAmount: selectedItemAmount}, boxClickYes);
        }
        //...
        $('#box .no').click(boxClickNo);
      });

This also demonstrates how to use the data property in jQuery click handlers to store data in between the time you attach the handler and the time you use it (instead of storing that data in a closure that will keep the scope chain in memory). Using inline-defined functions is fine when you're just using it right there (like the body of a $.each, for instance) but it's not OK when you're attaching event handlers.

Malathion answered 30/10, 2009 at 4:21 Comment(2)
dreamerscorp.com/test/test01/javascript_destory_test.html sample code here :) so you mean i have to unbind every event within the function and set all the functions to null?Flamen
By the way, stereofrog's "unbind before bind" is also a necessary part and you should definitely do that too.Malathion
D
14

You can try to nullify the function, or override it assigning an anonymous function that does nothing:

myFunction = null;
// or 
myFunction = function () {};

You can also do it within the function itself:

var autoDestroy = function () {
  autoDestroy = null;
  //...
  return 1;
};

autoDestroy(); // returns 1
autoDestroy(); // TypeError: autoDestroy is not a function
Digiacomo answered 30/10, 2009 at 4:14 Comment(5)
I don't think he's really asking how to destroy a function; rather, he's asking how to untangle the references that cause it to stay in memory.Malathion
@Anthony: Yes, I think we need to see his code to give an accurate answerPorcupine
@Robert: Thanks, with that kind of 'self-function redefinition' you can do really clever things: is.gd/4HMa2Porcupine
please wait, im trying to write a simpler sample code, coz the original code is too complected, and thanks for giving me a direction :)Flamen
dreamerscorp.com/test/test01/javascript_destory_test.html sample code here :)Flamen
R
6

to unbind events in jquery use unbind function http://docs.jquery.com/Events/unbind

$("something").click(function() {
    $("anotherOne").click(function() {
         ....
    });
});

in this example, every time "something" is clicked, an event handler is added to "anotherOne", so if you click three times, you'll get three event handlers.

$("something").click(function() {
    $("anotherOne").unbind('click').click(function() {
         ....
    });
});

here you're guaranteed to have only one click handler on "anotherOne".

There's no need to destroy previous handler explicitly.

Rutheruthenia answered 30/10, 2009 at 8:41 Comment(3)
by doing this if i have functions in $("anotherOne").unbind('click').click(function() { // functions here }); do they still exist? i mean does "unbind" just remove the event or it remove both the event and functions within the event?Flamen
what about using jquery's "one" function: $("something").one("click",function(){ $(this).one("click",function(){ }); }); It will execute once for each matched element and never again. docs.jquery.com/Events/oneKarb
@David Murdoch, i think its not suitable in this case, with "one" function, code inside the function can only be excute once. what i want is to destory the old handler when a new one is creat. :)Flamen
M
5

Basically you need to remove all references to those functions so that the JavaScript garbage collector can collect them. If they are bound, you need to unbind them. If there are other variables in there that point to them, they need to be set to null.

It might help if you posted some code; then we can give a better answer.

...EDIT:

What's happening here is, you're creating a closure that will outlive the containing function:

    function edit(){
      $('.edit').click(function(){
        //...
        function _edit(boxTitle,selectedItemAmount){
          //...
          $('#box .yes').click(function(){
            alert(boxTitle + ' for ' + selectedItemAmount + ' selected item');
            $('#msg').hide(); // hide msg box when yes btn is clicked
          });
        }
        //...
        $('#box .no').click(function(){
          $('#msg').hide();
        });
      });

In other words, inside a function, you're saying, "Attach this function to a DOM object," and you're doing it inline. JavaScript captures variables from outer contexts and keeps them alive while the reference to the inner context is alive.

What you need to do is to define the functions somewhere not inline and then use them:

    function boxClickYes(e) {
      alert(e.data.boxTitle + ' for ' + e.data.selectedItemAmount +
        ' selected item');
      $('#msg').hide(); // hide msg box when yes btn is clicked
    }
    function boxClickNo(e) {
      $('#msg').hide();
    }
    function edit(){
      $('.edit').click(function(){
        //...
        function _edit(boxTitle,selectedItemAmount){
          //...
          $('#box .yes').bind("click", {boxTitle: boxTitle,
            selectedItemAmount: selectedItemAmount}, boxClickYes);
        }
        //...
        $('#box .no').click(boxClickNo);
      });

This also demonstrates how to use the data property in jQuery click handlers to store data in between the time you attach the handler and the time you use it (instead of storing that data in a closure that will keep the scope chain in memory). Using inline-defined functions is fine when you're just using it right there (like the body of a $.each, for instance) but it's not OK when you're attaching event handlers.

Malathion answered 30/10, 2009 at 4:21 Comment(2)
dreamerscorp.com/test/test01/javascript_destory_test.html sample code here :) so you mean i have to unbind every event within the function and set all the functions to null?Flamen
By the way, stereofrog's "unbind before bind" is also a necessary part and you should definitely do that too.Malathion
E
1

To "destroy" a function in javascript, simply ensure that the function becomes unreachable. This will enable the function to be eligible for reclamation. One thing to watch out for is that javascript variables are bound based on scopes (not as individual variables) and a scope, with many unused objects, may persist if a binding is kept to the scope: to provide any more help requires knowledge of the specific code and how it is used.

Please see the javascript delete operator as one way of removing a variable or object member. Setting the value to null/undefined/other-object removes on method of reaching the object previously referenced (although it might still be reachable otherwise and thus not be reclaimed) but does not get rid of the variable/member.

delete variable
delete obj.member
delete obj[member]
Exemplar answered 30/10, 2009 at 4:51 Comment(4)
thanks for the help, i just tried using "delete" the function, but functions and variables within the deleted functions still exist.. the following is the sample code :) dreamerscorp.com/test/test01/javascript_destory_test.htmlFlamen
@Flamen I don't understand what you mean by still exist in this case. The fact that existence can be tested as positive implies that the objects are not eligible for reclamation (which implies that they do exist...) Is there a particular way this is being tested? What is the desired result?Exemplar
pardon me for my poor knowledge of javascript. what i mean by functions still exist is because they are in a "click" event and the "click" event is in a function called "edit" which is under selectable "stop" event ( pls see demo code ). so everytime i fire selectable there will be a new handler store in memory. i tried to declaimed the "edit" function as null or using the "delete" operator but it didnt work. i think my problem is like what Anthony Mills said. i shouldn't use inline-defined functions to attach event handlers. thanks for the help :)Flamen
@Flamen Don't make this over-complicated those "non-inline" functions are still object and still have an outer scope. The entire point of a "managed language" is that such trivialities are mostly ignorable. A possible exception were to be if large amounts of DATA was stored inside a scope that was kept alive for an extended period of time. However, otherwise, don't worry about such little details. Write your code to say what it does and does what it says. Premature optimization is a vile little trap.Exemplar

© 2022 - 2024 — McMap. All rights reserved.