JavaScript 'Import' a module into another module - javascript

I'm currently messing around with JavaScript to try and understand the language more. I want to make two different modules, one with generic helper functions and the other with specific functions to the problem.
How can I access functions from one module to another?

You have two options here. Both are fairly popular, so it's up to you which you choose.
The first is to define your helper module in the scope of your application module's parent:
var helpMod = (function(){
return {foo:"bar"}
})();
var appMod = (function(){
console.log(helpMod.foo);
})()
And the second is to directly import the module as a parameter to the closure function:
var helpMod = (function(){
return {foo:"bar"}
})();
var appMod = (function(h){
console.log(h.foo);
})(helpMod);
Direct imports are more explicit, but taking advantage of scoping can be easier - so long as you're comfortable with that variable in the global scope!

You would simply place the various functions into two separate files then reference them in a "sandbox" HTML page as follows:
helper.js
function helper_function() {
alert("this is a helper function");
}
specific.js
function specific_function() {
alert("this is a specific function");
}
index.html
<html>
<head>
<script src="helper.js"></script>
<script src="specific.js"></script>
</head>
<body>
<script type="text/javascript">
helper_function();
specific_function();
</script>
</body>
</html>

Related

function is not getting called in html [duplicate]

I am trying to accomplish a pretty simple thing: I have some code on a javascript module file and I import it on another javascript file (that doesn't export anything) and I want to call some of the defined functions in that file from the HTML directly.
Let's se some representative and minimal example of what's happening to me (actually tested the code and gives the exact same issue I'm experiencing with the real one, which is not really much more complex than this one):
module.js:
const mod = () => 'Hello there!';
export { mod };
main.js:
import { mod } from './module.js';
function hello()
{
console.log(mod());
}
main.html:
<!DOCTYPE html>
<html>
<head>
<script type="module" src="module.js"></script>
<script type="module" src="main.js"></script>
</head>
<body>
<button name="next-button" onclick="hello()">Obi-Wan abandons the high ground to salute you</button>
</body>
</html>
Without the import (and putting all the function definitions on a single .js file) I can call the function directly from the HTML. However, once I have introduced the modules I am no longer able to: it simply says that the "hello()" function is not defined.
I am completely new to ES6 modules (and to front-end javascript in fact), so I am fully aware all I just said is just lack of knowledge (or understanding), but I would appreciate any comment on what am I doing wrong and how to solve it so I can have my code in different files and be able to use it. Thank you all in advance!
Each module has its own scope. They are not sharing the global scope like "normal" scripts do. That means hello is only accessible inside the main.js module/file itself.
If you explicitly want to create a global variable, you can achieve that by creating a property on the global object, window:
function hello()
{
console.log(mod());
}
window.hello = hello;
See also Define global variable in a JavaScript function
Having said that, it's good practice to avoid global variables. Instead you can restructure the HTML to load the modules after the button was created and bind the event handler via JavaScript:
<!DOCTYPE html>
<html>
<body>
<button name="next-button">Obi-Wan abandons the high ground to salute you</button>
<script type="module" src="module.js"></script>
<script type="module" src="main.js"></script>
</body>
</html>
and
import { mod } from './module.js';
function hello()
{
console.log(mod());
}
document.querySelector('button').addEventListener('click', hello);

call function inside <script type="module"> from <script type="text/javascript>

Is there any way that use a function declared inside <script type="module"> from <script type="text/javascript>?
For example,
<script type="module">
function do_something(){ ... };
</script>
<script type="text/javascript">
do_something();
</script>
This is bad practice
You can explicitly make a variable a global, but modules appear to be loaded asynchronously so you need to wait until the module has been evaluated.
I'm using DOMContentLoaded here, but I don't know if that is reliable.
<script type="module">
function do_something() { console.log("Something"); } window.do_something = do_something;
</script>
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', (event) => {
do_something();
})
</script>
Instead of doing that, you should design your JS to not need globals in the first place.
Use a module as the entry point into your program, not a non-module.
Short answer, no (unless you wish to pollute the global namespace).
MDN Guide on modules states this clearly.
Last but not least, let's make this clear — module features are imported into the scope of a single script — they aren't available in the global scope. Therefore, you will only be able to access imported features in the script they are imported into, and you won't be able to access them from the JavaScript console, for example. You'll still get syntax errors shown in the DevTools, but you'll not be able to use some of the debugging techniques you might have expected to use.

Code patterns for JavaScript libraries

Among JavaScript libraries (jQuery, MathJax, marked Markdown rendering library, etc.), I often see various patterns:
Pattern #1
index.html
...
<script src="mylibrary.js"></script>
</body>
</html>
mylibrary.js
var mylibrary = (function() {
...
var myVar = ...
...
})();
Pattern #2
index.html
<html>
<head>
...
<script src="mylibrary.js"></script>
</head>
<body>
...
</body>
</html>
Same mylibrary.js
Pattern #3
index.html
<html>
<head>
...
<script src="mylibrary.js"></script>
</head>
<body>
...
<script>
mylibrary.run(); // explicitly needs to be run
</script>
</body>
</html>
Same mylibrary.js
Questions:
What's the purpose of the var mylibrary = (function() { ... })(); trick?
Is there a difference between pattern #1 and #2? (I would say no)
Is there any reason to prefer #3 rather than #2?
It seems that both could be interesting. Example for MathJax: pattern #2 makes sense (it would autoparse the DOM and render math formulas), it's what has been chosen by them (see this example). Pattern #3, requiring an action to actually run the rendering would make sense as well.
The purpose of that is that it's creating a modularized IIFE (Immediately Invoked Function Expression). This is useful to avoid polluting/assigning variables to the global namespace and helps prevent conflicts with other external plugins/dependencies that might appear in your app.
Yes. In the first your scripts are loaded in the head whereas your scripts are loaded in before the closing of the body in #2. It's recommend to load your scripts before the closing of the body so your page doesn't hang as it loads in your javascript files.
Go with #3 over #2. As to why, refer to point #1.
Update
Here's an example of how things would look if you were to simply assign a variable within the global namespace.
var exampleGlobal = "I'm an example global variable";
function one() {
exampleGlobal = 1;
}
....
function two() {
exampleGlobal.charAt(0);
}
one(); // Changes the exampleGlobal to a Number
two(); // Tries to use a string-based instance method but throws an error since exampleGlobal is now a number
Here we see that the exampleGlobal is exposed and available to all functions within this script. In this case it's very easy to err and change the value/purpose of this variable anywhere in your script. Here's where IIFE's come into play:
var exampleModule = (function() {
var privatized = "I'm only accessible within this module";
return {
privatized: privatized
}
}());
In the above we're creating just but one global variable that serves as a module and encapsulates values/functions that would only pertain exclusively to it. Try accessing privatized globally. You'll find that it returns undefined as it's not available within the global scope unless you explicitly invoke the module and it's return value:
var exampleModule = (function() {...}());
console.log(privatized); // undefined
console.log(exampleModule.privatized); // returns: "I'm only accessible within this module"
IIFE's are also advantageous in the fact that you can safely avoid naming conflicts that may occur within your app. As an example, jQuery and Mootools share the $ character to invoke their respective function calls. If you'd like to safely use the jQuery without any conflicts with Mootools you pass the $ object as an argument into your IIFE, which will then shield it from the global scope.
(function($) { // Here this is just the parameter we'd like to refer jQuery as
$('div');
}(jQuery)); // You pass in the actual jQuery object here which is when/where the function is immediately invoked.
You can't access myVar outside mylibrary.
See Should I write script in the body or the head of the html?
Pattern #3 gives you more control of when and how you actually use mylibrary.

Why I can't access a JavaScript function defined in a .js file from another .js file?

I am pretty new to JavaScript, and I was experimenting with the global scope following a tutorial.
In this tutorial I have 3 files:
1) index.htm:
<html>
<head></head>
<body>
<h1>HELLO WORLD !!!</h1>
<script src="app.js"></script>
<script src="utility.js"></script>
</body>
</html>
As you can see I include 2 JavaScript files.
2) app.js:
var person = 'Torny'; // When I call the logPerson() function this line override the person variable value into the global stack
//console.log(person);
logPerson();
3) utility.js in which is defined the logPerson() function defined into the app.js file:
var person = 'Steve';
function logPerson() {
console.log(person);
}
Ok, so I expected the following behavior:
Into the app.js file set the string 'Tony' as value of the person variable, the call the logPerson() function declared into the utility.js file and so print 'Tony' in the console.
The problem is that when I try to open the index.htm file into FireFox, I go into FireBug console and instead the 'Tony' value I obtain this error message:
ReferenceError: logPerson is not defined
So it seems that from the app.js file it can't see the logPerson() function that is defined into the utility.js file and imported.
Why? What am I missing? what is wrong?
In javascript the order of the files matters. You need to load the script which defines your function before you can use it. Switch the 2 <script> tags
<body>
<h1>HELLO WORLD !!!</h1>
<script src="utility.js"></script>
<script src="app.js"></script>
</body>
</html>
change
<script src="app.js"></script>
<script src="utility.js"></script>
to
<script src="utility.js"></script>
<script src="app.js"></script>
;) You try to get definitions from a script which is loaded later
greetings
First browser will parse the JS files.
If you see the order of script included
app.js
utility.js
So when it is parsing app.js. It sees logPerson() which is a function call not function definition. At this point of time the file utility.js is not parsed and the browser is not aware of that function also. (meaning till it reads utility.js).
So to solve this, call the logPerson api after dom-loaded, usiing body onload function.
The explanation is as simple as that Javascript code is interpreted on the fly: As one script is loaded, it is executed immediately.
So, you just have to declare the scripts in the right order of dependence.
You run the script which tries to use logPerson before you run the script that defined logPerson.
If you reverse the order of the scripts, it will work.
Function declaration hoisting only works within a given script.
In my case, it wasn't the <script> ordering that was the issue (as initially thought), but the scope in which the function was defined. To enable access of the function in other JS files, I made it a property of the object that is in the scope of those files. So now, it can be accessed as MyObject.myFunction wherever MyObject is instantiated.
(function ($) {
function MyObject(data) {
var myFunction = function(){
console.log('');
}
$.extend(this, {
// methods
"myFunction": myFunction,
});
}
}(jQuery));

calling a javascript function from a separate script?

I want to organize my JavaScript so I thought I would make a functions JS file. Is there anyway I can call the functions from functions.js from global.js?
EDIT
functions.js:
var get_selects;
get_selects = {
getLanguages: function() {
}
}
global.js:
get_selects.getLangueges();
Yes, functions defined at the top level are automatically available in the global scope (window in a browser), and this is typically not desirable.
Another approach that would mitigate this is to group your functions into a single object so you aren't polluting the global scope with a whole bunch of unrelated functions.
var utils;
utils = {
toast: function(message) {
alert("Notification: " + message);
},
sum: function(a, b){ return a + b; }
}
utils.toast('Email sent');
utils.sum(1, 2);
If both scripts have been included in the same HTML file, sure, it will work out of the box. Best way to know is to try it.
All .js files load top level functions into the global namespace. So, yes.
simply call it like anyother functions
yourFunctionName(yourFunctionParams);
be aware, you need to include your functions.js BEFORE your global.js, else it won't see your functions.
From the moment you include a JS in the HTML file, all the functions become available. So, if you make like this, it will work:
<script type="text/javascript" src="functions.js"></script>
<script type="text/javascript" src="global.js"></script>
But (as soon as I know), you must include "functions.js" first. Otherwise, "global.js" will not be able to find the calls. You can also make a little function inside "global.js" to include "functions.js" on the fly, like this:
function include(js_path){
//By Fabrício Magri e Micox
//http://elmicox.blogspot.com/2006/12/include-em-javascript.html
var new= document.createElement('script');
new.setAttribute('type', 'text/javascript');
new.setAttribute('src', js_path);
document.getElementsByTagName('head')[0].appendChild(new);
}
Than, on the beginning of your "global.js" you call this function to include the contents of "functions.js" on the section as soon as the browser requests "global.js"

Categories

Resources