Not really sure how to ask this, but I'm just looking for some insight/info.
If I'm including multiple JavaScript files in my app, how does the page/app see all the JS code. Does all the JS in all files become one-big JS file
If one JS file has a variable foo=true; and another JS file has foo=false, what is the scope of foo? Is it local to the script it is in or does it become seen in 'all' the js code?
Thanks for any insights.
Yes, for most purposes it's just like if there were only one file, built by concatenating all the files in the order of imports.
The differences :
"use strict"; (supposing it's present) is only valid per file
it's much slower for the browser to fetch 10 small files than a big one, which is why js developers building big applications usually concatenate (and often minify) all the files for production
The only thing the scripts share is the global scope; the separate parts don’t become one big file.
For example, you can’t do this:
<script type="text/javascript">
function hello() {
</script>
<script type="text/javascript">
}
</script>
And a 'use strict' in one <script> wouldn’t apply strict mode across all of them.
If you define in one file, without using var:
foo = true;
It will be a global variable, and it will be accessible by your second JS file when it does foo = false
All your scripts will share the same global namespace if they are defined in plainly on the page. To create a local scope for your variable, you'd have to wrap it in a function.
See the explanation provided in this question: What is the scope of variables in JavaScript?
To easily handle multiple JavaScript files and keeping the global scope minimal, while allowing the different scripts to share information, I recommend you try RequireJS (http://requirejs.org/), it is a JavaScript file and module loader. It will handle any file dependancies you may have and it'll load them asynchronously. It will also make it easy for you to pass variables amongst the different modules/files without having to expose them to the global scope.
There are other file/module loaders too. See: http://www.netmagazine.com/features/essential-javascript-top-five-script-loaders
Related
I am by no means a guru with JavaScript, so my apologies if this questions sounds "beginner". But why is it that if I have 3 JavaScript files in a project, that any of those 3 JavaScript files can call any of the other functions that are in the other JavaScript files?
The bigger question is how can this be stopped? an example would be if, of these 3 hypothetical JavaScript files, just say they are named as ManagerJS.js, TeamAJS.js and TeamBJS.js, I don't want TeamAJS to be able to access TeamBJS but I want them both to be able to access ManagerJS.
All scripts on a page are evaluated in global scope. There is a single shared global scope per page.
You can prevent access by not defining stuff in global scope. You can use an IIFE to create a private scope for each script:
// myScript.js
(function() {
// everything declared here is *local* to this function
var localValue = 42;
// we could expose values by explicitly creating global variables
// (but there are other, more elaborate ways)
window.globalValue = 21;
}());
Only expose values that you want other code / scripts to access. There are various ways to do that, one of them is the revealing module pattern.
See also What is the purpose of a self executing function in javascript?
It sounds like you want to use some kind of dependency injection system. There are quite a few options out there, including CommonJS, RequireJS, ES6 imports, and probably a lot of others.
Here's an example in CommonJS
// in TeamAJS.js...
// gain reference to Manager script
var Manager = require('./ManagerJS')
// do things with Manager
// note: can't access TeamBJS unless you require it as a dependency
module.exports = {
// put methods or variables in here that you wish to expose to other modules
}
The RequireJS site has a nice article on modules
Firstly, I understand text/babel is not for use in production, but I found it quite useful for development as when I make a change to my .jsx file django's dev webserver will reload without me having to do anything (i.e. compile the JSX to JS after every change).
I am not in control of the build environment (e.g. django) as this is a small plugin for a larger system that I am not developing.
The problem is this:
<script type="text/babel" src="{% static "myapp/js/main.jsx" %}"></script>
<script>
$(function() {
console.log(mything);
}
</script>
Where mything is in main.jsx, something as simple as:
var mything = "hello";
If main.jsx is javascript (and the type of the script tags is changed accordingly) then this will work just fine. As text/babel though, it will not work because mything is not in scope.
Uncaught ReferenceError: mything is not defined
This makes sense to me as I wouldn't expect script tags of different types to share a scope, but I'm wondering if there is some clever way around this to aid development?
I previously had all the code in a single text/babel block, but as it grows, it would be nice to separate it out into several JSX files.
Without diving too deeply into the Babel source (looking at https://github.com/babel/babel/blob/master/packages/babel/src/api/browser.js), I'm going to guess that it reads your JSX source, performs transformation on the source, and then evals the source in some way to execute it. The scope is not shared because babel prepends 'use strict'; to the transformed code (standard in ES6).
If you really need to expose a variable, you can attach it to window (ie use window.mything in your JSX instead of just mything). Ideally, you should make use of modules as you split your code up into multiple files. You can make use of a build step to transform your code through Babel and use browserify/webpack to manage dependencies.
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.
Writing some JS and would love to enumerate specifically what I'm importing from other files in the main body of my JS script. Is there an equivalent to C's extern declaration for JS?
Thanks!
Variables declared outside of function scope are global in JavaScript. For example, if you have two JS files and declare a variable 'myObject' in the first file, it will be in scope for the second file, and declared for use if the first file is loaded into the browser already.
If you need access to objects between JS files, it's good practice to expose one object to the global namespace and declare fields and methods on that object.
File 1:
var myObject;
myObject.myField = "Field!";
File 2:
myObject.prototype.myFunction = function () {
return this.myField;
};
Hope this helps, happy to hear other suggestions and open to corrections :D
There's no equivalent to a C extern declaration in JavaScript because JavaScript doesn't require variables to be declared before they're used the way C does.
If your JavaScript code depends on some properties being defined on the window object, just document those properties in a comment near the top of the file.
Sadly, Javascript has no built in features for controlling what gets imported or not.
By default, all sripts loaded in a page will write their global variables to the same shared global scope. The only way around this is writing your scripts so that they create as few global variables as possible, using the module pattern.
Alternatively you can use one of the module systems extensions that people came up with. For example you can write your scripts using the CommonJS module system and it will make it make it so that top level var declarations in your scripts arent seen from other scripts and lets you explicitly export the values you like. Some runtimes like nodejs can run CommonJS modules natively and for the ones that dont, like browsers, you can use a tool like browserify to compile the commonjs modules into a single file that can be put into a script tag and that will still do the right thing.
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.