I have a bunch of javascript "classes" (Prototype) that make up the inheritance hierarchy of a web application I'm building. I've been trying to organize these classes into "namespaces":
var UI = {
Control: Class.create(KVO.Object,
{
...
})
}
The classes are organized into separate files, so when I wanted to add a class to UI, I did this in a separate file:
UI.TextFieldControl = Class.create(UI.Control,
{
...
})
But, when I try to use UI.TextFieldControl in my program after including the files, it is undefined. I guess this is a scope problem of some sort, because within the TextFieldControl file it is defined, but as far as I can understand UI.TextFieldControl should be defined after it is included; what am I doing wrong?
Ok, I found the problem; I was including the file that defines UI twice, once before the file that defines UI.TextFieldControl and once after. Thanks for your responses; I was beginning to worry I didn't understand javascript scope at all!
Have you tries using FireBug? Because by the code you provided nothing seems to be wrong. If your file includes are fine. Your controls should be defined.
Use FireBug and check your files and their order of loading. Maybe your UI.Control is being loaded after you define TextFieldControl? You'll also be able to see your UI namespace if it hass all the necessery classes and also try defining them by hand and see what happens.
If you're using IE you probably forgot to remove some trailing comma, that simply discarded the whole file with your TextFieldControl...
Related
There are a lot of questions and answers about conflicting variables names on Stackoverflow, but they all seem to be about scoping in your own code.
<script src="https://external_one/some_script.js"></script>
<script src="https://external_two/another_script.js"></script>
I'm loading two external, 3rd party JS scripts and need to run them on the same webpage. Separately they work fine, but when I try to import both at the same time, I run into a problem: both scripts have been written in such a way that they use a global _ variable. This means only the script that was imported last will work, as it overwrites the existing _ variable from the first script.
Using a global variable like this is bad practice and using a generic variable name like _ makes it even worse, but as these scripts are rather complex I can't just write my own version and I'm stuck using the scripts from these two providers. They don't seem to provide something like the 'no conflict' option libraries like JQuery provide (to prevent breaking other script that use the $ variable).
So what I'm was trying to figure out, is if it's somehow possible to encapsulate those scripts on import and prevent them from using the same variable. The only option I could think of was to use ajax to load the script, maybe make some changes and then run it using eval but this sounds like a huge problem waiting to happen.
Any suggestions on how to solve this problem?
Basically, we have a massive core.js file with lots of jQuery calls that have no structure whatsoever. Example:
$(document).ready(function() {
$(document).on({
change: function() {
// some code specific to 1 view
}
},
"#some-id-name-that-may-exist-in-multiple-views" // like "bank-box"
});
// This code isn't even inside a closure, so it get's executed in all views but '.metadata' only exist in one, braking the whole system.
checkProgress($.parseJSON($('.metadata').text()));
Now, as the comment says, it has happened before that a whole section of the system breaks because of a JS error that usually happens due to the share of JS code. (Ironically, thanks to the sharing of said code, Continuous Integration caught it because of the only 1% of the code that's tested)
How do I justify the usage of separate JS files that holds view-specific logic, instead of a massive core.js that exist because of the "the browser would cache all of the JS on the first load" argument. Any resources or links are welcome.
On the other hand, maybe multiple files is an incorrect approach and we need to have 1 core.js file, but the code should be in a different way so that it doesn't conflict like it does right now. If this is the case, then how.
You can first check for the existence of those elements, that you are working on. You could rewrite your this code like this:
if( $(".metadata").length ){
checkProgress($.parseJSON($('.metadata').text()));
}// if $(".metadata").length
I am new to javaScript and am unsure how to go about creating a new js library and referencing this in another js file.
If I have a standalone file Utilities.js
var Utilities=
{
show: function(input)
{
alert(input);
}
};
Am I missing something as to how a library should be defined standalone?
My second question is how to use that is sub-sequent js files. What I did so far is:
<script type="text/javascript" src="resources/Utilities.js"></script>
In my index.html. Is this enough to reference it as:
Utilities.show("Hello");
In any other java script file?
I tested it in this fashion and got and error "Utilities is not defined"
NOTE: This is just an example and not my full and practical purpose.
Yes, including that Javascript file with that global variable declared is enough to call your methods this way Utilities.show("Hello"); from another Javascript file loaded after Utilities.js or inside a <script></script> section of your html.
But you can actually improve it a little, following the module pattern and exposing only the functions you really need to the global scope (you'll likely write some functions that the users of your library should not call directly, this allows you to do it in a clean way):
var Utilities=Utilities||(function () {
//Accessible only here
var privateArray=[];
//Cannot be called from outside this function
var privateFunction=function(){
}
//Return only what must be publicly accessible, in this
//case only the show() method
return {
show: function(input){
privateFunction();
alert(input);
}
}
})();
That (function () { /* Code */})();, defining a new scope for your code will also avoid name clashes with other global javascript object/functions.
It is OK to use object literals, but you can define libraries using other patterns (module, revealing module, constructors, etc).
I recommend these links to understand primitives, scopes, closures, object literals, etc.
http://bonsaiden.github.io/JavaScript-Garden/
http://jsbooks.revolunet.com/
To call the method inside index.html you need to add a tag.
<script>
Utilities.show("Hello");
</script>
But this approach it's not recommended. Instead of it, you can create a new JS file to run your library code.
<script type="text/javascript" src="resources/Utilities.js"></script>
<script type="text/javascript" src="resources/main.js"></script>
In main.js
Utilities.show("Hello");
Hope it helps.
Given the fact that you gave, within yout question, zero context of what you're trying to achieve, the best answer to your original question is that it depends.
If you just need a bunch of files and you're done (like in your example, Utilities.js and a few more) then you're ok with the way you're heading to.
But of course, you'll allways want to scale your front end and thus you should adhere to some architectural pattern. So, if you're building a client side (browser-side) application, then you should really implement your libraries using the module pattern, and begin your project from a good project example / scaffold.
On the other hand, if you're rendering the html on server (e.g. you're using PHP to render the final html file that will be sent to browser) and you just need some thin functionality in the browser, the way you begun can be okay if you're careful. Also, you can still implement the module pattern here too, although I strongly suggest that you should make use of namespacing to have a clear separation of concerns.
In browser based javascript you can't just call functions from different files yet. In Es6 there are ways. But not yet. Which mean just because you have some variable or function etc then you cant reference it automatically in another file.
Unless both files are loaded into one html and are loaded in order.
Alternatively you could run task runner like grunt and 'merge' them upon each build.
Javascript doesnt have special concept of library, in es6 it's a little different, everything is an object.
What you are doing is just creating an object. and yes it will work.
I'm trying to experiment with [this library](https://code.google.com/p/autotags/ in meteor).
First, when I tried to install all the individual javascript files to client/compatibility folder, I get an error message when calling AUTOTAGS from the constants js file:
AUTOTAGS = { ... } // autotags-js-core.js
AUTOTAGS.TAG_CONSTANTS = [ 'news','research','favourite' ]; // autotags-js-constants.js
It kept saying that AUTOTAGS was undefined. I deduced from reading about global scope that any external library with VAR that you want to have global scope, put it under compatibility.
If that's correct, then why isnt the scope global when putting all individual files under lib/external? AUTOTAGS = {..} without var means its available to entire application right?
Instead, I got the scope to work by combining all the javascript files in one single js file under lib/external. I thought I understood, but it gets worse.
Within a single js file - any function that begins with a closure is local to that FILE, and not global scope, whilst any function assigned to variable name makes it a global variable?
function(something() { ... } ) // closure, local
generateTags = function() { ... } // global scope?
var generateTags = function() { .... } // is this local or global?
If the var generateTags function is local, then putting it under client/compatibility will make it global? Lastly! - I get the vague notion that I should define global variables under lib/environment.js from here - https://github.com/oortcloud/unofficial-meteor-faq#where-should-i-put-my-files, is that true?
There are actually two questions here. One is about how the scope works in javascript, the other about integrating the autotags library into a meteor project. Since the answer for the first one should be relatively easy to find somewhere else, I'll only try to answer the second question.
The reason you are getting this "undefined" error is not a scope problem but it is somehow related to the order in which the files are loaded into your meteor app. Namely, autotags-js-constants.js comes before autotag-js-core.js because constants precedes core in the alphabetic ordering. In consequence, the AUTOTAGS variable is not defined at the point when the autotags-js-constants.js file is being parsed.
One simple way to overcome this issue is to rename your files, so as to enforce the right loading order. Another way is to use a tool that will enable you to define dependencies between files. If you are interested please take a look at require project, which is basically a lightweight and meteor friendly implementation of the core requirejs features.
However, probably the best solution is to create a custom smart package. It would allow you to explicitly define the order in which the files should be loaded. Just take a look on some existing smart packages to get the idea on how this should be implemented. I would also recommend using meteorite to manage your custom smart packages.
I have three javascript files that I want to merge into a single file. Is it possible to just copy paste all of the code into one file or will there be namespace conflicts and other problems?
EDIT: I'm worried that each file acts like a namespace encapsulating each file's code, and that this encapsulating will cease to existing if I merge the files.
If the script files were all loaded in the <head> and you paste them in the same order they appeared in the HTML then there shouldn't be any problems.
Having said that, if they use document.write I'm not sure...
If they all work when loaded sequentially, it makes no difference if you concatenate them to a single file and you that instead. Just make sure you put them together in the same order as when you load the seperately.
In answer to your edit: No, each file will not act as a separate namespace.
The top level in each file will share the same global namespace. Hence the having single file with the contents of all three is the same as referencing each seperately assuming the content appears in the same order.
Try it and see if it works. :) The namespace conflicts will depend solely on the code, so without posting it, it will be hard to tell you. You shouldn't have problems putting them in one file so long as they don't have errors already, but if one is dependent on another, make sure you put them in the proper order.
There's absolutely no namespace encapsulation in JavaScript, unless you go out of your way to make it happen. By default, everything ends up in the global namespace. The JavaScript module pattern helps reduce global namespace pollution.