jQuery - functions moving to window.function - javascript

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. :-)

Related

Removed JavaScript is still executable

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.

How can I call a function within a closure within a variable?

I'm a newbie in java but the code is below the explanation
This is code from a game but the problem is: Take the navigator function, I click the navigator in the game and some sort of (ajax?) goes on and it gets logged. But when I use my FireBug console I cannot send a message with the functions above the return line.
Essentially.. The only functions that ThisFunction.* shows is the ones returned at the bottom. How can I invoke the Navigator function? I've tried:
ThisFunction.a.navigator(args here);
, but it says a is undefined.. it doesn't show in the autocomplete list either.
** I removed the code because it is from a game. Thanks for the help! **
You somewhat nailed it on its head with this bit:
The only functions that ThisFunction.* shows is the ones returned at the bottom
That is the expected and purposeful functioning of the language.
Short answer: You have to return out of the closure anything that you want to be externally accessible... That could be the a variable, or it could be an api that could itself access the a variable while keeping it private from the exterior. This is called lexical scoping and it is your friend.
Example time:
var ThisFunction = (function() {
var a = { navigator: "woot" };
var b = function() {
return a;
}
});
ThisFunction.a; //a is null/undefined on the returned
ThisFunction.b; //b is defined yay
var aOUTSIDE = ThisFunction.b();
aOUTSIDE.navigator; // "woot"
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures
So the only things that can get at A are the things that were var'd up in the same "scope" as a. So either you return A out of the scope or you return something from inside the scope that provides an API to either get at A, or to execute some of A's internals...
Depending on what OTHERFUNCTIONSHERE is, you can access it from within one of those functions, if they close over the variable a (why such cryptic var names by the way?). Otherwise, it's out of scope.
Given that you're using Firebug, ThisFunction.%a.navigator(... args) should work (.% is a Firebug-specific extension to the language). But as noted in other answers, it's impossible from pure JavaScript.

global.getElementById('...') is null or not an object

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.

How do I find where a variable is defined at runtime?

I've been using jQuery and YUI side-by-side with no issues until recently. Occasionally, inside of a callback for, say, a YUI button, $ will be shadowed by some other function (click for big version):
and for the life of me, I cannot figure out why this is happening. Yes, I know I could be safe and use jQuery or window.$ everywhere instead of just $, but that's just a workaround and not an actual fix.
At runtime, how can I find where this $ impostor is coming from? - e.g. find where it's declared, and why it's in my bleedin' scope.
It turns out that this behavior is easily reproduced (at least in Chrome and Firefox 4) right here on Stack Overflow, since SO uses jQuery (again, click for full size):
I can only infer that $ as
function () {
return document.getElementById.apply(document, arguments)
}
must be from the console itself!
Found it.
with strikes again.
Chromium bug for this: http://code.google.com/p/chromium/issues/detail?id=70969
I'm betting this doesn't happen in IE? This is the only hint I could find:
http://davidwalsh.name/dollar-functions
http://dam5s.tumblr.com/post/3079779011/bug-in-chromes-javascript-console
Some sort of bug in Chrome/Firefox/Safari.
Here's something to try. Firebug's debugger shows you all the variables that are available at a scope, in your example, it's obviously not local scope, and it's also not global since you already tested window.$. Therefore, it's has(?) to be a closure variable (which should be in the same file).
The attached screenshot shows the closure scopes that are available
The example shows that data is available within $.each as a closure variable. Again, according to my theory, you should be able to find the culprit by looking for instances of $ on the page, since closures are lexically defined . Maybe there's a self calling function that passes in $ like jquery plugins.
you could try using jquery.noConflict
http://api.jquery.com/jQuery.noConflict
Use a watch expression...
Setup a function that checks if $ is correct, maybe jQueryCheck(), and alert if not correct.
function jQueryCheck(){
if(!$.filter)
alert('wtf');
}
Add a breakpoint at some step before you expect a problem to occur in the code.
Add a watch expression that runs jQueryCheck().
Hit breakpoint and just keep clicking on next step. When the variable becomes invalid the alert will pop up and you will then be on the line after the change occurred.
Here is code I used to test
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js"></script>
<script>
function invalid(){
/* set breakpoint on loop below
click invalid button
add watch expression jQueryCheck()
click nextstep repeatedly until wtf alert
*/
for(var i=0; i<100; i++){
if(i == 10)
$ = 10;
}
}
function valid(){
$ = jQuery;
}
function jQueryCheck(){
if(!$.filter)
alert('wtf');
}
</script>
<input type="button" onclick="valid()" value="run valid">
<input type="button" onclick="invalid()" value="run invaid">

Have Firebug break when a global variable x is defined

We have a very large JavaScript application, where after many months of coding there have inevitably sprung a couple scope slip ups where a variable is defined without using the var keyword in the following fashion:
function() {
x = 5; ...
}
instead of:
function() {
var x = 5; ...
}
This is happening somewhere - we're not sure where - and searching for the variable name in question is difficult, since it's a common word that appears 1000s of times in our source.
Is there a way to ask Firebug to break on the line that first creates a given global variable? To clarify, I would like to break at exactly the instant when window.x switches from undefined to a defined value, and to break statement.
I've tried creating a watch expression and hoped I could turn it into a breakpoint, but I can't seem to create watch expressions without some kind of context or scope.
If this isn't possible with Firebug, I'd be interested in anything that can accomplish this in Firefox in general.
Provided a few things
You know the name of the variable
You don't have a variable with that name in the global scope (declared outside functions), but only inside functions.
There are calls to the function that declares the variable.
this little script would do the trick:
<script type="text/javascript">
window.__defineSetter__("x", function(value) { console.trace(); });
x = 1;
</script>
You'll get a trace of the executed code before that assignment.
It may fail to report some situations, so take a look at JSLint. Load all your JS files right there and lint them.
Here's another solution that only works in Firefox because it uses the Firefox-specific watch method.
Put this piece of Javascript at the very top of your html page, just after the <head> tag:
<script>
window.watch('x', function() { debugger });
</script>
Note that watch works on any Javascript object (window is the global Javascript object).
Here's the solution I ended up using by modifying Ionut G. Stan's solution:
window.__defineSetter__("name", function(value) {
if (value=="div") {
debugger;
}
});
I used debugger instead of console.trace(), so I could stop and look at it mid-execution. With console.trace() I got a bazillion trace statements due to this line executing many times.
The leaky scope turned out to be buried in Dojo, where Dojo is setting that variable to the name of a processed element.
View your web page on the SeaMonkey browser (I use version 1.1.16) and look at the error console, you will see a message of this type for each assignment to an undeclared variable :
Warning: assignment to undeclared variable x
Source File: http://....js
Line: ##
In addition to debugging, I would advise to check your code with JSLint, which reports unexpected assignments in the global scope as errors.
There are several command-line bundles of jslint, such as jslint4java which can be used cross-platform in Ant build scripts.

Categories

Resources