Scope and closure (5): modules
April 07, 2018
⏳ 3 min read
Getting the hang of it
function myModule(){
var testString = "im testing";
var hi = "hi";
function test(){
console.log(testString);
}
function hi(){
console.log(hi);
}
// more functions...
}
function test
has a closure over the scope of the function myModule
. Nothing really special is going on here.
function myModule(){
var testString = "im testing";
var hi = "hi";
function test(){
console.log(testString);
}
function hi(){
console.log(hi);
}
return {
test: test;
hi: hi;
}
// more functions...
}
var moduleTest = myModule();
moduleTest.test();
moduleTest.hi();
And here are some important points:
test()
andhi()
cannot be invoked without invokingmyModule()
. Without it, the creation of the inner scope and the closures would not occur.- The object we return has references on it to our inner functions, but not to our inner data variables. We keep those hidden and private.
- It is not required that we return an actual object (literal) from our module. We could just return back an inner function directly.
And from this we can deduce two important conditions for a module: 1 There must be an outer enclosing function, and it must be invoked at least once (each time creates a new module instance). 2. The enclosing function must return back at least one inner function, so that this inner function has closure over the private scope, and can access and/or modify that private state.
Modules with IIFE
You can enclose the module to give it a truly private scope. This means you could invoke the module multiple times and you don’t have a confusion in the references of variables.
var moduleTest = (function myModule(){
var testString = "im testing";
var hi = "hi";
function test(){
console.log(testString);
}
function hi(){
console.log(hi);
}
return {
test: test;
hi: hi;
}
// more functions...
})(); // you could pass parameters down if you want
moduleTest.test();
moduleTest.hi();
Modules in ES6
- In ES6, each file is a separate module.
- ES6 modules do not have an “inline” format, they must be defined in separate files (one per module).
- The contents inside the module file are treated as if enclosed in a scope closure, just like with the function-closure modules seen earlier.
testString.js
function test(testString){
console.log(testString);
}
export test; // export functionName
hi.js
function hi(hi){
for(let i = 0; i < 3; i++)
console.log(hi);
}
export hi;
output.js
import test from "testString"
// import arbitraryNameForObject from fileNameWithoutExtension
// used when you want to import selective functions from a module
module hiMachine from "hi"
// module arbitraryNameForObject from fileNameWithoutExtension
// used when you want to import the whole module
test("I'm just testing"); // logs "I'm just testing"
hiMachine.hi("hey"); // logs "hi hi hi"
For more
see Mozila for help. In fact, these are all the possible ways to import (copied from this link):
import name from "module-name";
import * as name from "module-name";
import { member } from "module-name";
import { member as alias } from "module-name";
import { member1 , member2 } from "module-name";
import { member1 , member2 as alias2 , [...] } from "module-name";
import defaultMember, { member [ , [...] ] } from "module-name";
import defaultMember, * as alias from "module-name";
import defaultMember from "module-name";
import "module-name";