Are JavaScript functions in different <script>s in global scope? - javascript

I have a situation like this in an HTML file:
<script>
var my_function = function(param)
{
alert(param);
}
</script>
<div>
<!-- snip -->
<script>
$(function() {
my_function("Hello world!");
});
</script>
</div>
Will my_function be in scope in the second <script>? Wouldn't my_function be in global scope?

Yes, it will be, since it’s on the global object (as window.my_function).
It will also be ”in scope” (not really meaningful to check, but delete window.my_function won’t work, for example).

All scripts that execute on a page share the same document and window element. So yes. they execute in order, and they are all in the document scope.

my_function as defined in your code is added to the global scope. It will be available in all contexts. This is also how libraries can be made use of. Consider that the script tag contains executable code wether the code is inline:
<script>code</script>
or references remote code:
<script src="my_code.js"></script>
So when you add a script like jQuery or backbone to your html page you are effectively adding their contents to the pages execution context and can access them from your own code.

Related

Access HTML element later in document through JavaScript

I am just starting out with JavaScript and I have a simple code that sends a value to an element with id p. I am currently declaring this function in a <script> in the <head> element of my document.
function writeP(resultSet) {
document.getElementById('p').innerHTML = resultSet.length;
};
writeP(results);
When I have this listed within the <head> element and run the webpage, firebug throws this error at me: TypeError: document.getElementById(...) is null.
However, if I move the code block into a <script> tag beneath the element and then reload the webpage, no problems and the script works as it should. Is there any reason for this, and a way I could make this work so I wouldn't have to define my functions beneath the element or include a onload on my body element?
Thanks for your help
Reason is that by the time your launch js code, DOM is not yet prepared, and JS can't find such element in DOM.
You can use window.onload (docs on W3schools) trigger to fire your functions after all elements are ready. It's same as having onload property on body element, but is more clear, as you can define it in your js code, not in html.
JS evaluates syncronically. Therefore, it does matter WHEN you declare the function. In this case, you're declaring it before the element actually exists.
Second, when you declare a function with that syntax, it does get eval'd inmediately. If you declared, instead
var writeP=function(resultSet) {
document.getElementById('p').innerHTML = resultSet.length;
};
you could save just the call to the end of the Doc, and leave the declaration at the beggining.
However, I would advise you to read a few jQuery tutorials to learn easier ways to deal with dom manipulation. Nobody runs raw JS for that task anymore.
jQuery includes an useful call to document ready event, which will save you a lot of headaches and is -IMHO- more efficient than the onload event. In this case, you would include the jQuery library somewhere in your code
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
and then add
<script>
jQuery(document).ready(function() {
var writeP=function(resultSet) {
jQuery('#p').html(resultSet.length);
};
writeP(resultSet);
});
</script>
just about anywhere in your document or an external js file, as it suits you.

when has a function to be in $(document).ready()

I just don't get it. I searched and searched but for this I just can't figure out what's "right".
There are three examples.
1) Fiddle 1.0
Here we have html with onlick="function" and the javascript function right there as well which works fine
<span class="classic one" onclick="someFunction(this,'one')">CLICK HERE</span>
<script type="text/javascript">
function someFunction(obj,nr) {
var string = $(obj).attr('class');
$('.result').text( string );
}
</script>
2) Fiddle 2.0
Then when I move the function to the script section (kind of move it to the .js file) I get an error "ReferenceError: someFunction is not defined"
THIS IS WHERE THE QUESTION BEGINS
3) Fiddle 3
So now I have a function in document ready calling with .on(click which always works fine. This function is calling another function which is outside the docuemnt.ready() and also works fine.
So the question. When do I have to define the functions where AND WHY so it always works?
Thank you!
All the code from Example 3) looks like this:
<div class="result">result</div>
<span class="classic one" onclick="someFunction(this,'one')">CLICK HERE</span>
<span class="classic two" onclick="someFunction(this,'two')">CLICK HERE</span>
<span class="classic three" onclick="someFunction(this,'three')">CLICK HERE</span>
<span class="classic four" onclick="someFunction(this,'four')">CLICK HERE</span>
<div class="ready">ready</div>
<span class="callOtherFunction">Call other function</span>
<script type="text/javascript">
$(document).ready(function(){
$('.ready').text( 'dom is ready' );
function someFunction(obj,nr) {
var string = $(obj).attr('class');
$('.result').text( string );
}
$( "span.callOtherFunction" ).on({
click: function() {
$(this).css("color","red");
$(this).addClass("xyz");
otherFunctionCallingFunction($(this));
}
});
});
function otherFunctionCallingFunction($me) {
$('.callOtherFunction').append( ' --> ' + $me.attr('class') );
}
</script>
A lot of what you're seeing is because of jsFiddle's very surprising default setting, which is to wrap the code in the script pane in an onload handler. So your code is wrapped in a function and no longer at global scope (which is where functions need to be if you use onclick-style attributes). You can change this with the drop-down box on the left (the second one, under the list of libraries and scripts). Change it to "no wrap" to have unwrapped code.
You're not (by far!) the first to be bit by this surprising default.
Answering your main question:
when has a function to be in $(document).ready()
If you control where the script tags loading your script go, you basically never have to use ready; instead, just make sure your script tags are at the end of the HTML, just before the closing </body>.
You can use ready, of course. The reason for doing so is to make sure that all the DOM elements have been created before your code runs. But if you put your script tag at the end, that's already true. You can still define your functions outside of the ready handler (if you want them to be globals), but if you're using ready, you would call them from the ready handler so the elements exist.
FWIW, I would avoid using onclick-style attributes for hooking up event handlers, primarily because they require you to create global functions. I prefer to avoid creating any global symbols when I can avoid it.
The general form I'd recommend:
<!-- ...your page markup here... -->
<script src="any_libraries_you_need_if_you_are_not_combining.js"></script>
<script src="your_script.js"></script>
</body>
</html>
where your script looks like this:
(function($) { // A scoping function that wraps everything
// Hook up event handlers here. You can use `$` for jQuery, even if
// you've used noConflict, because we have a private `$` symbol (see
// the `$` argument above)
// The body of your code goes here
})(jQuery); // <== Note how we're passing the jQuery reference in
// and immediately executing the scoping function
Here's a complete example: Live Copy
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>Script Placement Example</title>
</head>
<body>
<input type="button" class="hello-button" value="Click me">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<script>
// This would be in a file, rather than inline
(function($) {
// Hook up handlers
$(".hello-button").click(sayHello);
// Body of the code
function sayHello() {
$("<p>Hello!</p>").appendTo(document.body);
}
})(jQuery);
</script>
</body>
</html>
In JavaScript, scope is handled on a per-function basis. Anything in scope of a function can access other things in scope of that function and things in a wider scope.
Defining a variable with var inside a function will limit the scope of that variable to the function.
Defining a function with a function declaration inside another function will limit the scope of the defined function to the container function.
When you use ready, you pass a function to it. Anything defined in that function is, of course, scoped to that function. Since it is scoped to that function, it is not a global. Your onclick attribute isn't defined in the scope of that function, it can only access globals. This is why you get a reference error.
Avoid globals. They make things hard to maintain. Avoid onclick attributes, they usually depend on globals.
You need to use ready if you want code to run after the DOM has been fully constructed. This is useful if you want to bind event handlers to elements in it with JS (e.g. with jQuery.on). Do this rather then using onclick attributes.

calling javascript function from html doesn't work

here is the problem..
i have a javascript file which is named javascript.js like this
$(document).ready(function(){
function init()
{
//code goes here
}
}
now the index.html file has a command button which should call the init() function.
<html>
<head><script src=javascript.js ....></script>
<body><button type="button" onclick="init()">Call Init!</button></body>
</html>
But it doesn't call it. Nothing happens as expected. Please suggest a solution.
You should define your function outside $(document).ready() scope.
The onclick attribute will be executed in a global context. Your init function is scoped to the anonymous function which you pass to jQuery. Three solutions:
Move the init function outside of the ready function, into the global scope
export the init function by making it a property of the global object: window.init = function() {…};
as you use jQuery, you should not need to define any handlers in attributes. Instead use (inside the ready function): $("button").click(function init() {…}); Even better use an id to reference the button.
Try viewing the page in chrome. Hit F12 to view the console. You'll be able to quickly debug the issue. At first glance, however, I do see that your $(document).ready function is not closed properly. Add ');' at the end of the code you included. Also, add quotes around javascript.js in your script tag. See if that helps.
Why don't you use
function init()
{
$(document).ready(function() {
//code goes here
});
}
You can use flag too in order to keep track if the "//code goes here" proceeded or not. So in case of document not ready yet, you can use while loop with setTimeOut function for some pause interval "In order to not hang the client browser".

Why isn't my JavaScript working in JSFiddle?

I can't find out what is the problem with this JSFiddle.
HTML:
<input type="button" value="test" onclick="test()">
JavaScript:
function test(){alert("test");}
And when I click on button - nothing happened. The console says "test not defined"
I've read the JSFiddle documentation - there it says that JS code is added to <head> and HTML code is added to <body> (so this JS code is earlier than html and should work).
If you do not specify the wrap setting it defaults to "onLoad". This results with all JavaScript being wrapped in a function run after result has been loaded. All variables are local to this function thus unavailable in the global scope.
Change the wrapping setting to "no wrap" and it'll work:
http://jsfiddle.net/zalun/Yazpj/1/
I switched the framework to "No Library" as you don't use any.
The function is being defined inside a load handler and thus is in a different scope. As #ellisbben notes in the comments, you can fix this by explicitly defining it on the window object. Better, yet, change it to apply the handler to the object unobtrusively: http://jsfiddle.net/pUeue/
$('input[type=button]').click( function() {
alert("test");
});
Note applying the handler this way, instead of inline, keeps your HTML clean. I'm using jQuery, but you could do it with or without a framework or using a different framework, if you like.
There is another way, declare your function into a variable like this :
test = function() {
alert("test");
}
jsFiddle
Details
EDIT (based on the comments of #nnnnnn)
#nnnnnn :
why saying test = (without var) would fix it ?
When you define a function like this :
var test = function(){};
The function is defined locally, but when you define your function without var :
test = function(){};
test is defined on the window object which is at the top level scope.
why does this work?
Like #zalun say :
If you do not specify the wrap setting it defaults to "onLoad". This results with all JavaScript being wrapped in a function run after result has been loaded. All variables are local to this function thus unavailable in the global scope.
But if you use this syntax :
test = function(){};
You have an access to the function test because it's defined globally
References :
https://stackoverflow.com/a/338053/3083093
https://stackoverflow.com/a/5830423/3083093
Change wrap setting in the Frameworks & Extensions panel, to "No wrap-in <body>"
There is no problem with your code.Just choose the extension onLoad() from right side.
<script>
function test(){
alert("test");
}
</script>
<input type="button" value="test" onclick="test()">
Select OnDomready
HTML:
<input id="dButton" type="button" value="test"/>
JavaScript:
addEventListener('load', init, false);
function init()
{
oInput = document.getElementById('dButton');
oInput.onclick = test;
}
function test(){
alert("test");
}

Cannot get declared variables in javascript

Consider a javascript file script.js which contains the code alert(theVar);
Now, i linked the js file to the document like
<script type="text/javascript">
var theVar= 'a alert';
</script>
<script type="text/javascript" src="script.js"></script> //Contains alert(theVar);
The variable theVar is used and i get a alert. This works fine.
When,
<script type="text/javascript" src="script.js"></script>
<script type="text/javascript">
var theVar= 'a alert';
</script>
is used, i am not getting a alert.
I know the problem is because of the variable, which is declared after loading the js file.
But is there any way to get the variable declared anywhere in the document ?
in script.js do
window.onload = function() { alert ( theVar ) }
Or your favorite library dom ready fn, so it invokes the callback after a certain event instead of immediately.
Though, this really depends on what kind of functionality script.js has, which you have not specified thus far.
The important bit is that code gets executed in the appropriate order. You should delay the call to alert(theVar) until the document gets fully loaded. For instance, you can attach an onload event handler to the window object.
It's also worth noting that calling external *.js files does not affect the way code gets run.
The simple solution:
Move the script.js inclusion to the last row of the body. That way a variable declared at any point in the document can be used.
The technical solution:
Inside script.js, hook on to the window.onload event before doing any evaluating. The result is the same as with the simpler solution, but allows you to keep you script tags in the head (or anywhere for that matter).

Categories

Resources