Iam a new guy in JS and iam doing a mobile project in phonegap, i want to know how to keep a variable in overall page scope, not global variable since it will eat lot of memory which is not acceptable for a mobile developer, i have two or more JS tags in a page as shown,
<script type="text/javascript">
// script one here
</script>
<html> //html block here </html>
<script type="text/javascript">
// script two here
</script>
so i request your valuable suggestion & help. Thanks!
"Overall Page scope" is global scope.
JavaScript scoping (generally, except for specific esoteric scopes*) works in two ways:
Global scope
Closure scope (the scope created by a function)
Since you can't share a function over script tags, a global is your only choice.
Consider passing messages to share data instead of a global.
Here is how something like this could be done with message passing:
Script 0:
window.pubsub = (function(){
var subscribers = [];
return {
subscribe:function(user){
subscribers.push(user);
},
publish:function(message,data){
subscribers.forEach(function(elem){
elem.onMessage(data);
});
}
};
})();
Script 1:
(function(pubsub){
var someObject = {}; // to share state
//code here
pubsub.subscribe(someObject);
someObject.onMessage = function(){
//whatever you do when you get a message
};
})(window.pubsub);
Script 2 would be identical, only it would handle messages differently.
This way, you have one global variable (if that's too much, you can even delete window's reference to it after subscribing script 2, which would mean no globals at all)
*technically try/catch and with also introduce scope, but they're very rare and should not be used like this
Related
One of the views in my Rails 4 app loads a simple javascript to create an instance of the Ace editor once the page loads...
$(function() {
var editor = ace.edit("editor");
}):
In that view, I have a simple ajax button...
<%= button_to "Set Content", {controller: :pages, action: 'set_content'}, remote: true %>
that requests some unobtrusive javascript...
editor.setValue("New content has been set");
but this doesn't work. I'm guessing this doesnt work because editor isn't defined. Since ajax calls fail silently and I don't know how to debug unobtrusive javascript code using the same Chrome tools that I use debug normal javascript code, I can't verify that's the actual problem, but that's my best guess.
I was under the impression that if I write var editor, then is declared as a global variable that my unobtrusive javascript should be able to access.
My questions are...
How can I access global variables inside of my unobtrusive javascript code?
Since global variables are considered evil, is there a better way to access the editor variable from my unobtrusive javascript?
Thanks in advance for your wisdom!
when you use the var keyword inside a function, the scope of that variable is local to the function, so you are incorrect in your assumption about global scope. To make the variable global, declare it outside of your function:
var editor;
$(function(){
editor = ace.edit('editor');
});
alternatively you could simply reference the window object (which is the 'global' object in browsers
$(function(){
window.editor = ace.edit('editor');
});
With regards to avoiding global variables, it is reasonable to use a single global variable (often called 'app', or 'myCompany' or such to provide a namespace that is globally accessible.
var app = {};
$(function(){
app.editor = ace.edit('editor');
});
This at least limits the scope of your new variables so you don't mistakenly overwrite global variables. However the real answer to avoiding global variables lies in the overall architecture of your app, which can't really be addressed without seeing more code. Generally speaking if ALL of the code you write is inside your jquery ready function, then you don't need global variables. Frameworks such as angular, ember, and backbone provide a much better structure for this type of thing than the ad-hoc code common with simple uses of jquery.
$(function() {
var editor = ace.edit("editor");
});
creates a local variable editor within the context of it's callback function. To access it elsewhere, you'll need to make it global window.editor = ace.edit("editor"), or add it to a namespace with something like
window.App = {};
App.editor = ace.edit("editor");
I have an MVC 4 project that utilizes javascript bundling.
In my _Layout.cshtml page I have something like this:
#Scripts.Render("~/bundles/scripts/desktop/modernizr",
"~/bundles/scripts/desktop/jquery","~/bundles/scripts/desktop/jqueryui",
"~/bundles/scripts/desktop/jqueryvalidation", "~/bundles/scripts/custom")
There are others, but this is just an example. Within one of my scripts that's called in the custom script I need to reference a global variable that set within the ready function, as shown below:
<script type="text/javascript">
$(function () {
//alert('Page is ready!');
var warning = 10;
var timeout = 20; }); </script>
Problem is, I always seem to get an error within the method that requires the warning and timeout variables. Am I missing something obvious (not to me, though!) on how I should create these variables? Should I var them outside the $Ready, because the js is loading before the page is technically ready?
Where should the global variable go, if everything is already in a render bundle and there are no script blocks?
Thanks!
The warning and timeout variables aren't global. They've only been defined within the function that you provide to the $ function.
I'd generally recommend avoiding global variables where possible, but if you really want to create global variables just use this:
<script type="text/javascript">
var warning = 10;
var timeout = 20;
</script>
Or this:
<script type="text/javascript">
$(function () {
window.warning = 10;
window.timeout = 20;
});
</script>
Thanks for the response.
I don't think adding the variables in the Ready page will work. The functions that require these variables are loaded before the page is 'ready' (per my understanding how this all works), so there are situations on a new page load where the variable will be required but unreferenced.
This is how I'm currently handling it:
I created a new .js file, with the following:
var warning;
var timeout;
Then I created a bundle reference to the file and put it into my #Script.Render stmt in the correct order for scope. Now, I have my global variables, and it's cleanly implemented into my view code. Now, I know that I should be passing around variables vs. having them global, but in this case I don't see a major issue.
I was actually going through this link. which explains how we can share global variable across multiple js. but the point is what need to be done if I am getting some variable into one js and need to pass to another one mentioned in same document after the 1st one.
approach which followed was:
Script 1 <script type="text/javascript" src="js/client.js"></script>
body added some hidden input with id myHiddenId, where values are set using client.js
Script 2 <script type="text/javascript" src="js/anotherJS.js"></script>
inside script 2 I am simply using $("#myHiddenId").val(); and using for my purpose.
I want to know whether I am following correct approach, because that hidden field may have some data which client should not get aware of. is there any other way through which I can pass the variable values across the js files ? Since I am at beginner level hence digging up some resources/books but still no luck.
If the client should not be aware of the data then you should not be using client side JavaScript. Any JavaScript executed in the browser can be debugged and viewed by the user.
You should always handle sensitive data on the server side.
Saving the variable in the JavaScript file or in the hidden element makes little difference.
Regarding using variables across files then you should be able to use any variables declared in Script 1 in Script 2 provided they are declared in the root scope and that Script 1 appears before Script 2 in the DOM.
<script> // Script 1
var root_scope = 'This variable is declared at root';
function some_function() {
// Variables not defined at root are subject to the scope they are in
var non_root = 'This is not at root';
}
</script>
<script> // Script 2
// Use the variable declared in Script 1:
alert(root_scope); // This variable is declared at root
// Note: declaring at root is the same as assigning to window
alert(window.root_scope); // This variable is declared at root
alert(typeof non_root); // undefined
</script>
I am currently coding in this way:
<script type="text/javascript">
var linkObj;
Is this a safe way to store data? My concern is what if a jQuery or other plug-in was to also use the variable linkObj. Also if I declare my variable like this then can it also be seen by other functions in scripts located in other js files that I include?
$(document).ready(function(){
var linkObj;
});
as long as you use the var keyword, any variable defined in that scope won't be accessible by other plugins.
I you declare a variable this way it will be accessible to all scripts running on the page.
If you just want to use it locally, wrap it in a function:
(function() {var linkObj; ... })()
However, this way nothing outside of the function will be able to access it.
If you want to explicitly share certain variables between different scripts, you could also use an object as a namespace:
var myProject = {}
myProject.linkObj = ...
This will minimize how many global names you have to rely on.
Wrap it in a closure:
<script type="text/javascript">
(function() {
var linkObj;
// Rest of your code
})();
</script>
This way no script outside your own will have access to linkObj.
Is this a safe way to store data?
This is not storing data per se, it's only declaring a variable in a script block in what I assume is an HTML page. When you reload the page in the future, it will not hold previous values.
My concern is what if a jQuery or other plug-in was to also use the variable linkObj.
That's a valid concern, like others have pointed out. However, you would expect plugins not to rely on scope outside the plug-in. This shouldn't impact a lot as good plug-in design would likely prevent this from happening.
Also if I declare my variable like this then can it also be seen by other functions in scripts located in other js files that I include?
Yes. As long as their execution is triggered after your script block gets loaded. This normally follows the order in which your script declaration appears in the page. Or regardless of the order they appear on the page if they are executed, for example, after the jQuery DOM 'ready' event.
It's common to hear that is good to avoid 'global namespace pollution', which relates to this concern. To accomplish that you can use a function to contain code, and directly invoke that function in your script block.
(function () {
var a = 1; // the scope is within the function
alert('The variable a is equal to: ' + a);
}) (); // the parenthesis invoke the function immediately
I need to send data in a HTML page to a script file that is loaded in that page. The simplest way i can think of is to use a global variable which is defined in the page and accessed in the script file.
We all know global state is bad, so i started thinking about the options available for passing data from HTML page to script file without using global state. I cant find (or think of) any.
I am curious whether this is possible. Any ideas?
It really depends what you're doing. In general, I wouldn't advise this methodology, but it's something to consider depending on your circumstances. For the sake of this example, I'll assume you're using jQuery (if not, replace the document.ready with whatever you want to use for onDOMReadyStateChange monitoring).
In the HTML:
<script type='text/json-data' id='some_data_set'>
{ 'foo': 'bar', 'baz': 1 }
</script>
In the JavaScript:
$(function() {
var myData = JSON.parse($('script#some_data_set').html());
// YOUR CODE GOES HERE
});
Nope. All the javascript scope starts from a global level, therefore you must have at least one global reference to your data.
Let's say you wanted to store a list of products and events:
var myGlobalData = { "products":<products>, "events":<events> };
Where <products> and <events> are two different data blocks.
If you're paranoid on global objects, you can simply delete the reference point (thus it's contents) after you finished using it, as follows:
delete window.myGlobalData;
One option is to scope your data. For example, in JS file you can define an object like:
var processor = {
function setData(o) { // do stuff
}
};
Then in your HTML you know that the data is scoped to the processor. So you can do something like:
processor.setData({someData});