I've got the following Javascript situation:
// First file - the one that I can't edit
(function(){
"use strict";
function test() {
alert("a");
}
test();
})();
This is defined in a Javascript file which I cannot edit. How would I go about overriding the test() method?
Redefining the function doesn't work. The output is still "a".
// My file - trying to override the first file's test() function
(function(){
function test() {
alert("b");
}
})();
Do you have any other suggestions?
In my mind the test() method must be defined somewhere, right? And if it is defined, I can override it.
Assign the function to a variable to create locally scoped functions that will behave the same within it's own function scope.
A scoped variable has priority over a global variable. So if you define a local variable in your own function you're overriding the other defined one. within the scope you're working in of course. On the outside of your scope the global object still persists.
You can't override a function in another scope. That is why a scoped function is scoped. It will keep a reference to it's local scoped variable. That's why the scopes are generally used, so you can encapsulate and protect your code to assure your code keeps working as intended.
unless it's a publicly exposed method, you can't override it.
(function(){
var test = function() {
alert("b");
}
})();
(function(){
"use strict";
function test() {
console.log("a");
}
test();
})();
(function(){
var test = function() {
console.log("b");
}
test();
})();
The text of the file can be edited if file is requested using XMLHttpRequest or fetch, then set edited response text to .textContent of script element, append script element to document.
Related
While debugging, I always use Firebug and try to call functions and show variables. However I can't when the function or variable is defined within $(document).ready.
How can I access these variables? Can I type something like a namespace, like document.ready.variableName or how can I see this?
Thank you in advance.
Global variables and functions can be created by assigning them as a property of window:
$(function(){
window.foo = function foo() {
// …
}
});
foo() should be accessible anywhere after that handler is executed.
How can I access these variables?
Well, you can't. Everything that you define inside an anonymous function such as what you are using in the $(document).ready is scoped to this anonymous function. It's private and not accessible to the outside.
So you could put your console.log inside the $(document).ready if you needed to inspect some private variable that is defined in its scope.
That's what debugging is for. In all major browsers (including IE), you can set breakpoints in the javascript code. When this is done the script halts and you can inspect your variables.
Here some links:
http://getfirebug.com/javascript
http://www.jonathanboutelle.com/how-to-debug-javascript-in-internet-explorer
How do you launch the JavaScript debugger in Google Chrome?
It depends on how you declare the variables inside the .ready() function. If you do var x = "test", then no, they are only accessible inside the scope of the ready function. If you do something like x="test", then that is available in the global scope and you can just access it like alert(x); or alert(window.x);
You probably don't want to define variables inside the ready function though if you are trying to use them outside the ready function.
Declare the variable in global scope:
E.g.
<script type="text/javascript">
var globalVar = null;
$(document).ready(
function() {
globalVar = "This is the value";
}
);
function TestFunc() {
alert(globalVar);
}
</script>
Here, if you call the TestFunc() anytime after the page load, you will see the value assigned in the ready() function.
Not sure I fully understand the issue, but couldn't you just declare the variables outside of document ready?
var a = "bar";
$(document).ready(function(){
a = "foo";
});
If you're using firebug, you should be able to call console.log within document ready, which might give you what you're looking for.
If you have
var x = "foo"
$(document).ready(function(){
alert(x); // foo
});
You can see the x variable anywhere, but if you you declare a variable y into the document ready It'll be only accessible within the document ready:
var x = "foo"
$(document).ready(function(){
alert(x); // foo
var y = "bar"
alert(y); // bar
});
alert(y); // undefined
I have some functions inside of functions and I am having trouble retrieving a variable. It will be easier to show in code I want to log the var three in the testit function but not sure how to do so.
test();
function test(){
var abc;
function one(){
abc = 1;
two();
}
var three;
function two(){
console.log(abc);
three = 2;
testit();
}
one();
}
function testit(){
console.log(three);
two();
}
to make test an object you would do the following:
function test(){
this.abc = 0;
this.three = 0;
this.one();
}
test.prototype.one = function(){
this.abc = 1;
this.two();
}
test.prototype.two = function(){
console.log(this.abc);
this.three = 2;
}
test.prototype.testit = function(){
console.log(this.three);
this.two();
}
and run it like so:
testObj = new test();
testObj.testit();
hope this helps.
edit: BTW: if you put a call in function 'two' back to function 'testit' you'll end up with an infinite loop.
Here's an explanation of what's happening:
When you wrap code in a function, you get what's called function scope. This means that the scope within the function belongs to the function and not to a scope above or outside of it (whichever way you want to look at it).
A closure allows an expression (typically, a function, as MDN states) to have it's own scope while sharing the scope of it's outer or higher scope.
So, let's look at an example:
// This represents the global, or window, scope.
// Analogous to window.outer_var.
var outer_var = 'outer var';
function outer_func() {
// New scope! Local only to outer_func and those
// expressions (functions) *enclosed* by
// `outer_func(){...}, e.g. inner_func(){...}.
var inner_var = 'inner var';
// Only outer_func() or inner-enclosed (to
// inner_func()'s definition) functions can
// access inner_func().
function inner_func() {
// Another new scope! Can access inner_var
// and inner_func_var (below). outer_func()
// canNOT access inner_func_var, though.
var inner_func_var = 'inner func var';
}
}
outer_func(); // Of course, it's in scope and accessible.
inner_func(); // This will cause ReferenceError: inner_func is not defined error.
Simply as it is (no wrapping context, with a closure), var outer_var is created with the global or window scope. It may be accessed in all of the following:
console(window.outer_var);
function outer_func() {console.log(outer_var);}
function inner_func() {console.log(outer_var);} No matter where inner_func's defined.
Here, #2/3 are analogous to:
function outer_func() {console.log(window.outer_var);}
function inner_func() {console.log(window.outer_var);}
Or global this:
function outer_func() {console.log(this.outer_var);}
function inner_func() {console.log(this.outer_var);}
Now, inner_var is accessible from the following:
function outer_func() {console.log(inner_var);}
function inner_func() {console.log(outer_var);} Only from within outer_func().
inner_func() may also only be accessed within outer_func(), because it belongs to the outer_func() scope, and thus is not visible/accessible outside of outer_func()*.
Lastly, inner_func_var is only accessible by:
function inner_func() {console.log(inner_func_var);} Only within outer_func().
To access your three variable, you have three choices:
Make three globally accessible (globals are generally discouraged as they may easily introduce difficult to resolve bugs when one is overwritten by some other code).
Return three from your test() function. In this case the value is accessed, not the actual variable within the function.
Create a property as #logic8 demonstrates, so it may be accessed as a property of an object.
* This isn't entirely true. outer_func() could export a reference to the function out of scope with return inner_func;. This is a more advanced concept, though, and won't be addressed here in depth. Here is an example.
You have to put it in a global to do so:
test();
var three = false;
function test(){
[..]
}
function testit(){
console.log(three);
two();
}
when you declare a variable with var it becomes local to that scope. If you want to access three in both functions, you can either declare it without var (making it global - generally frowned upon for good reasons) or declare it outside of the two functions: var three;
The correct way to do this is by using the closure pattern in javascript. This wraps your javascript class in its own function so anything you declare within that file is only local to your code.
Using jQuery, this is easily accomplished like so:
(function($){
//your code goes here
})(jQuery);
People typically do it this way so their javascript only executes when the page is ready:
$(document).ready(function(){
//your code goes here
});
It's a bit more complicated without jQuery if you want to execute your code when the document is ready:
document.addEventListener('DOMContentLoaded', function(){
console.log('document is ready. I can sleep now');
});
With your code, it would look something like this:
$(document).ready(function(){
var test = function(){
//test code here
};
var one = function(){
//one code here
};
var two = function(){
//two code here
};
var three = function(){
//three code here
};
var testIt = function(){
//test code here
};
});
This way, you can safely access all of your functions from the others without polluting the global namespace.
I had this code:
Javascript
(function() {
function read() {...}
})();
HTML
<body onload="read()">
Console said, read is undefined.
After deleting the IIFE it worked, why?
Thanks. :)
Here's a long but satisfying explanation about JavaScript scope and closures.
Since you declare read inside a function, it is local to that function.
Anything you declare inside a function will be local to it.
You can explicitly put it into global scope by assigning it as a property to window:
(function() {
function read() {...}
window.read = read;
})();
Writing
(function() {
function read() { ... }
})();
Is very nearly the same thing as writing
(function() {
var read = function() { ... } //this is different, but not significantly so
//for purposes of teaching this point
})();
and I think you should already understand why a var declared inside a function is not available outside of that function's scope.
The behavior of a function definition (function read() { ... }) is slightly different from the behavior of assigning a function expression to a variable (var read = function() { ... };) in terms of when the name of the function and the function become associated, but the two are otherwise identical.
Because it isn't defined globally. It's only been defined within the scope of that immediately invoked function. To make it global either use this:
function read() {...}
(function() {
...
})();
Or this:
(function() {
window.read = function() {...}
})();
Or better yet, just bind the onload event within the immediately invoked function:
(function() {
function read() {...}
window.onload = read;
})();
In this case the definition of read is inside the IIFE. This limits the scope of the function to the IIFE and any child functions inside of it. The handler for onload is executed in the global scope and hence doesn't have access to read
A couple of days ago I have learned on my own example how bad global variables and functions are. So apparently the best solution is NOT to use them, however sooner or later I will need to reuse my variables and functions over and over again.
So my question is: Can I reuse my functions and variables without declaring them globally? Can it be done?
For example, I want to reuse my alertBox function and my containsP variable couple of times:
DEMO: http://jsfiddle.net/ajmyZ/
//I am BAD GLOBAL FUNCTION inside var
//But I am reusable!!!
var alertBox = function () {
alert("Hey I am BAD function!!")
}
$(document).ready(function () {
//I am BAD GLOBAL var
//But I am reusable TOO!!!
var containsP = $("div p:first");
containsP.click(function () {
alert("Hi BAD var HERE!!");
});
$("p").eq(1).click(function () {
alertBox();
});
//I am the NICEST function here
//but I am NOT reusable :(
$("p").eq(2).click(function () {
alert("I am the NICEST function here!!");
});
});
I guess the simplest way to avoid clobbering the global object is just to create your own "application context". You can do that, by creating a self-invoking function which wraps your whole js-code within each file.
(function( win ) {
"use strict";
var still_global_but_only_in_this_anonymous_closure = true;
$(document).ready(function() {
// ...
// accessing the global object:
win.some_global_property = true;
});
}( this ));
Actually, you're already creating such a local context with your anonymous function you pass into .ready(). This is just the more explicit way. That self-invoking method, just calls itself with the global object as argument (where you still can explicitly access global variables). Furthermore, by invoking "use strict"; you're protected from accidently creating global variables alá "Ops_I_Forgot_The_Var_Statment = true;
The code you posted has no global variables. A variable declared inside of a function (in the case of your example, the anonymous document.ready handler) will never be global unless you make one of two mistakes:
forget the var keyword, making an implicit global
explicitly say window.myVar = ...;
On some JS code on some sites I see Javascript code such as this:
SomeName.init = (function () {
// some stuff
})();
I mean, this is not a jQuery plugin code such as this:
(function( $ ){
$.fn.myPlugin = function() {
// Do your awesome plugin stuff here
};
})( jQuery );
Then, what is it? and what is the resulting JS object?
It's a anonymous function, which doesn't leak variables to the global scope when declaring variables using var.
SomeName.init = (function () {
return 3.1415;
})();
SomeName.init is a number (3.1415), because () after the anonymous function declaration executes the function. There's no way to obtain the original function, unless defined within the anonymous function:
(function foo(){
//foo refers to this function
too = foo;
})();;
//foo is undefined
//too refers to the function, because `too` has been defined without var
The Module Pattern. And those two snippets have more in common than you think.
(function () {
// some stuff
})()
is a anonymous function that calls itself instantly. It's just a closure around the code inside to stop the variable scope becoming global.
Whatever the function returns.
(function() {
//...
})();
Is used as a way to namespace code, or declare self-executing constructors. The resulting object is whatever that self-executing function returns.
The second snippet doesn't return anything and there is no resulting JS object.