If I have the following JavaScript code:
<script id="someJS">
var boom = 'boom';
function example(){
alert(boom);
}
</script>
and then do:
$('#someJS').remove();
I can still call example() even though that JavaScript function is no longer inside the DOM... How can I remove it?
I don't want to null the actual function(s) and variables with: boom = null; example = null; as I don't always know what is inside the JavaScript file. For example the function names, variables, etc. I need to be able to remove the entirity of what was inside that script tag.
Update: For those that wanted to know the user case for this:
Basically in an app I am working on, we have custom JavaScript added for certain clients that when a button is clicked e.g. save, then checks if certain functions exist and then runs them. However because this save button is generic it means that that the custom code gets called all the time after it's added even if it's no longer relevant.
The solution we have come up with (someone had posted this as an answer but they removed it for some reason) was to namespace it all like:
DynamicJS = {
boom: 'boom',
example: function(message) {
alert(message);
}
}
And then we can just do: delete DyanmicJS;
Which removes all the functions and variables inside this namespace from the global scope, effectively binning off what the script file added.
Although I am sure this is not a perfect solution as if you had event listeners inside the file, I'm sure they would still exist!
How can I remove it? I don't want to null the actual function, as I don't always know what is inside the JS file.
You can't. Script code is executed, creates things in the JavaScript environment, and is completely disconnected from the script element that loaded it. Other than completely reloading that environment, if you don't know what the code did, you can't undo it.
Even if you could infer some of what the code did (for instance, by making a list of globals before and after), while you could remove new globals you detected (or at least set them to null or undefined, since delete doesn't work wiith globals added via function declarations or var), that doesn't tell you what event handlers, web workers, etc. the code may have hooked up.
$('#someJS').remove(); only removes the script element from the page.
By the time the element is removed, the script has already been interpreted, which means example has been added to the global scope.
To properly remove that function you could do this:
window.example = null;
However, apparently you don't want to do this, and this will result in a load of errors if there's script elsewhere that actually uses example.
An alternative could be to assign an empty function to it:
window.example = function(){};
This will prevent the "removal" from resulting in errors.
(Aside from the function not returning values when that may be expected)
Once the function has been processed, it is now part of the window's executable list of functions - regardless of if you remove the original source or not.
To remove the function entirely, try:
window['example'] = null;
However, based on your last comment:
I don't want to null the actual function, as I don't always know what is inside the JS file.
It sounds like you want to maintain reference to the function but not have it executable directly? If that's the case, you can store a reference to it and remove the original:
var _exampleBackup = window['example'];
window['example'] = null;
To call it, you can now use:
_exampleBackup();
And to restore it, if you need to:
window['example'] = _exampleBackup;
example();
That function is still in the window.
Code that you put inside a script tag will be ran when the element is created and has no value (roughly) by itself anymore. Removing the tag will not affect the document and the impact it had on it (generally).
To remove the function you need to remove the example property on the window object, which is how the function will be defined, running the code above.
$('#someJS').remove();does nothing more than removing the text from the DOM, but does nothing to the actual function (nor the file), since it is parsed and executed.
In order to delete the function, you could either set it to null or simply overwrite it with example=function(){};
JavaScript Hoisting
There is a concept in JavaScript called Hoisting. In this phase, compiler parse all JavaScript code and declares variables and function at the beginning of scope. In your case, function example and variable boom is already declared and kept in memory. When you run that method, interpreter will call that method and interpret it instead of interpreting actual JavaScript code. You are deleting script block after it went in memory. And thats why it is still executable.
Approaches to do this
1) Use object oriented approach. Add your method in a object, and when you want to delete it, delete that property by using delete.
2) Create one variable which holds a function which contains your code to execute, and set that variable undefined when you want.
Related
Is there difference between :
(function() {
/*..........*/
})();
and :
(function($) {
/*..........*/
})(jQuery);
Other people explained what the difference is, but not why you use the latter.
The $ variable is most often used by jQuery. If you have one script tag that loads jQuery and another that loads your code, it's perfectly fine. Now throw prototype.js into the mix. If you load prototype.js and then jQuery, $ will still be jQuery. Do it the other way around and now $ is prototype.js.
If you tried to use $ on such a page, you'd likely get errors or weird behavior.
There are many questions on StackOverflow about this problem. Plugins shouldn't assume much about the page they're loaded in, so they use this pattern defensively.
i am asking if there is difference between (function(){/…/})(); and (function($){/…/})(jQuery);
A little difference. In case of (function($){/*…*/})(jQuery); and absense of jQuery you'll get an error message immeditally after page loads. It's a simpler to detect jquery absense or incorrect order of scripts inclusion, when jquery-based code included before jQuery.
In case of (function(){/*…*/})(); you'll get an error message when code inside this construction actually call one of jQuery methods. It's harder to detect this error, but on the other side you can include your jquery-based scripts before jquery.
I prefer first case.
The second form, (function($){/*…*/})(jQuery); can be slightly safer when working in an environment where you don't (or can't) strictly enforce what code gets put on your site.
I used to work on a large site with a lot of third-party ads. These ads would often unsafely inject their own version of jQuery and occasionally they would override jQuery's global $ object. So, depending on how we wrote our code, we might be calling methods that no longer existed or had slightly different behaviour from what we expected. This could be impossible to debug, since some ads would never appear in our area or were excluded from our environment. This meant we had to be extremely protective of scope, inject our dependencies before any ad code had a chance to load, namespace anything that had to be global and pray no ad screwed with us.
Other answers are quite fragmented so I'd like to give a more detailed answer for the question.
The main question can be self-answered if you understand..
What does (function(argument){ /*...*/ })(value); mean?
It's a quick hand version of:
var tempFunction = function(argument){
/* ... */
}
tempFunction(value);
Without having to go through the hassle of conjuring up a new terrible name for a function that you will only call once and forget. Such functions are called anonymous functions since they aren't given a name.
So (function(){/*...*/})() is creating a function that accept no argument and execute it immediately, while (function($){/*...*/})(jQuery) is creating a function that accept one argument named $, and give it the value of jQuery.
Now that we know what the expression means, surely the first think on our mind is
"Why?". Isn't $ jQuery already?
Well, not exactly. We can never be sure. $ is an alias of jQuery, but other libraries can also use the same alias. As user #FakeRainBrigand already pointed out in his answer, prototype.js also use $ as its alias. In such cases, whichever library assigns its value to $ later wins out.
The practice of (function($){...})(jQuery) is very similar to an alias import in other programing languages. You are explicitly telling the system that your function:
Requires an object/library named jQuery, and
Within your function, $ means jQuery.
So even when someone include a new library later that override the alias $ at the global level, your plugin/framework still works as intended.
Because javascript is so... "flexible" in variable assignment, some people (including me) go as far as doing things like
var myApplication = (function($, undefined){ ... })(jQuery);
Apply the same understanding, it is easy to interpret the second argument part as: assign nothing to the variable undefined. So we can be sure that even if some idiot assigned a value to undefined later, our if(checkVariable === undefined){} won't break. (it's not a myth, people really do assign values to undefined)
When is it commonly used in javascript?
This anonymous function practice is most commonly found in the process of providing encapsulation for your plugin/library.
For example:
var jQuery = (function(){
var publicFunction = function(){ /* ... */}
var privateFunction = function(){ /* ... */}
return {
publicFunction : publicFunction
}
})();
With this, only jQuery.publicFunction() is exposed at the global scope, and privateFunction() remains private.
But of course, it is also used any time you simply want to create a function, call it immediately, and throw it away. (For example as a callback for an asynchronous function)
For the bonus question
why they used (function(){}() twice in the below code?
Well, most likely because they don't know what they're doing. I can't think of any reason to put nested function in like that. None at all.
(function(){/*...*/})(); does not set $ as reference to jQuery within IIFE and (function($){/*...*/})(jQuery); sets $ or other parameter name; e.g.; (function(Z){/*...* Z("body") where Z : jQuery*/})(jQuery); as reference to jQuery within IIFE
The they are both closures. The first is just an anonymous function that will fire any well formatted code that is inside immediately. The second is the jQuery closure. It is how the jQuery library initiates it wraps its code in the JQuery object and exposes it isn't the $ symbol.
(function(){}()) // this is a closure
(function($){}(jQuery)) // is a closure that wraps the executed code inside of the jQuery returned object and exposes it via the $.
With this (function(){/*…*/})();, you are not passing any argument to the inner function, while with this (function($){/*…*/})(jQuery); you are passing jQuery as argument to the inner function and expecting its value as $(which means, you will be able to use jQuery inside the inner function).
Ex:
(function($){
$(document).ready(function() {
console.log('all resources loaded');
})
})(jQuery);
They both are examples of Immediately Invoked Function Expression. In that sense, there is no difference between (function(){/*…*/})(); and (function($){/*…*/})(jQuery);. So no benefits are gained by wrapping (function($){/*…*/})(jQuery); inside (function(){/*…*/})();
A new execution context is created when a function is executed. So when (function(){/*…*/})(); is executed a context is created. Again when (function($){/*…*/})(jQuery); is executed, another context is created. Since the first context is not used (i.e. no variables are declared inside it), I don't see any advantages gained by the wrapping.
(function() { // <-- execution context which is not used
(function($) { // <-- another execution context
"use strict";
/*..........*/
})(jQuery);
})();
I create a new global object and then put everything in to that new object so it doesn't interfere with anything else anyone else does. After calling the document.ready() function this gets moved to window.bf for unknown reasons. I've reduced this down to a simple example. Anyone have any ideas on what is happening?
<html>
<head>
<title>Test</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
debugger;
var bf = {}; // Namespace
bf.vars = [];
bf.vars['onclick'] = "";
$(document).ready(function() {
bf.noop = function() {}
bf.noop();
window.bf.noop();
});
</script>
</head>
<body>Test</body>
</html>
So I wind up with two "bf"s. One is the original global object and the second one is the window.bf object. My problem is: Originally, the global object had all of the functions and variables in it. Now the global variable has nothing except bf.vars (an array). Everything else is now in the window.bf object (including everything that was supposed to go in to the global bf.vars array yet I never asked for that to happen.
Up until last Friday (9/25/2015) this did not happen. Now it does.
Update: I just tried removing the document.ready() function. If you remove the document.ready() part - then the global bf object goes back to being a global variable. So this appears to have something to do with jQuery itself.
Before anyone asks: The reason the document.ready() is being used is because some of the functions I define make reference to locations that need to be loaded and jQuery says to use the document.ready() function in order to ensure all elements have been loaded before execution starts. The bf.noop() function is just to give an example of a function and to show that the function no longer shows up in the global bf object.
Screen capture with document.ready():
Screen capture without document.ready():
Better?
In the top-level scope of a script tag, all variables get implicitly attached to window.
The good news is, you actually don't have two bf objects, you only have one with two ways to access it.
var bf = {};
bf.foo = "bar";
document.getElementById('output').innerHTML = JSON.stringify(window.bf, undefined, 4);
<div id="output"></div>
A variable declared outside the scope of a function is bound to the global scope. Since you're declaring var bf = {} inside the script tag, its parent is the window object.
This MDN document is a good read on variables in JavaScript.
Rossipedia has both two good answers as well as leading me to find the problem. See his posts.
For unknown reasons, jQuery version 1.11.1 (I'm using v1.11.3 and thus the 1.11.1|3 in my post) has some kind of an error that was fixed in jQuery version 2.1.3.
But I also found that one of the programs I use to generate the menu for our site was generating an old function name (showIt instead of show_menu) which was causing problems also. By fixing the generated function name the problem has gone away.
This does NOT mean that the jQuery folks can go "Yeah! We don't have to fix anything!" because this is a valid error and the simple code I posted shows how to break jQuery which might mean there is some way to cause real problems with jQuery. So basically, this should be looked at by someone more in tune with jQuery to find out why the code I posted does what it does. Then they can come back and say "You idiot! You did BLAH! and you shouldn't have!" or maybe "Thanks for locating this really obscure problem that no one else in the entire world has come across or cares about." In any event - this is now a known problem. :-)
I have a declared variable and jQuery code telling a button to store a form's value as the value of that variable and execute a function.
var verb = "";
$( "#submit" ).click(function() {
verb = $('#enter').val();
teConjugate();
});
In the teConjugate() function, I have placed a lot of functions and variables using the "verb" variable that I want to use outside the teConjugate() function. However, when I declare these functions and variables globally, they use the globally declared "verb" (which is an empty string). I've done research and I know that it has something to do with the rendering of the page (as console.log does not raise the same issues).
The only thing I've thought of is putting said functions and variables in to a initialize function which executes on button click, to reduce the hassle of copy pasting everything. However, this did not work either.
Is there any solution? Any help would be appreciated.
JSbin with the dilemma.
As one can see, there are a lot of variables and functions that would be more useful outside the function.
There is nothing wrong with what you have shown here (see this fiddle). I suspect it is something to do with your teConjugate(); function.
In my project, I have designed a JavaScript page to render HTML data but I'm getting the above error. My code is:
global.getElementById('divPartnerGrid').innerHTML = "<table width='100%'><tr><td align='middle' style='vertical-align:middle; position:centre;'><img src='../Content/images/ajax-loader(2).gif'/></td></tr><tr><td align='middle' style='vertical-align:middle; position:centre;'>"+loadingLabel+"...</td></tr></table>"
While running the project,it will break at this line. Can anyone please let me know, what caused this error to come?
I don´t know what global is either but the getElementById method is defined on the document so you probably simply want
document.getElementById('divPartnerGrid').innerHTML = "...";
replace global with document, even if global is a variable you created that points to window (or this in the global scope), you still need a document in which you want to search for elements.
Also, make sure the page is loaded before this script runs: you can't get an element if it's not loaded yet
You have probably copied the global thing from an example that has encapsulated the global variable while you haven't done the same.
This is done in the following example where the document (which is probably what you want to use as others have pointed out) where document is sent in to the self envoking function so that global inside that scope would actually refer to document.
;(function(global) {
global.getElementById(/* */);
})(document);
This is typical for libraries that could be used on the server where the global value may be different from the one in a browser.
So I found this piece of code and it obviously works (as it has been in production for years):
window[someMethod] = function (tmp) {
callback({prop:"val"}, tmp);
// Garbage collect
window[someMethod] = undefined;
try {
delete window[someMethod];
}
catch (e) { }
if (head) {
head.removeChild(script);
}
// head refers to DOM head elem and script refers to some script file elem
};
Curious to know, how does it work?
How can it set itself to undefined within its body and try to
delete itself?
Does the browser know to not execute the undefined and delete until the call is finished? And how?
If the browser deletes it right away, then what happens after? Does the last line run?
Finally, do you guys see this leaking memory? If yes, how?
It's not setting itself to undefined, it's setting a reference to itself to undefined. If you think of a function as a block of code in memory, that block of code isn't deleted in this case, just the reference to it. You never explicitly delete anything in JavaScript, you simply remove references to it and leave it to the garbage collector to clean up. Note, this might not be the case for actual code, just heap objects, as its up to the engine how to treat it (interpret it, compile it, execute it on an abacus, whatever)
Based on that logic, once the function is executing, the original reference to it is no longer required as it was needed only initially to transfer execution to it.
You're misunderstanding JS evaluation as requiring a reference to it for every statement. In all likelihood, this method has been Just-In-Time compiled and is now executing just like any other non-JS function would run.
There are no apparent memory leaks in the code above.
Hopefully this is making sense.
Remember you can't ever explicitly delete something in Javascript. All you can do is remove all the references to it and so let the garbage collector remove it on the next cycle. By the end of this function, the function itself is still in memory, but there are no external references to it. Next time the GC runs, it will spot this and deallocate its memory.
window[someMethod] is simply a reference. Only the reference is deleted, not the function itself.
Once the function is done, and all reference to it are removed, garbage collection should take care of it, avoiding memory leaks.