Are export const statements visible inside the file they reside? - javascript

Are export const statements visible inside the file they reside?
export const MAX_NAME_LENGTH = 20;
console.log(MAX_NAME_LENGTH); // can I do this?

Yes, they are. The declaration is still a declaration in the scope in which it appears (e.g., the module's scope, since export can only appear there) and all the usual rules about the declaration apply; all export does is export it.
In that specific case, since it's a const declaration, the "usual rules" include the temporal dead zone above the declaration in which MAX_NAME_LENGTH cannot be used. If you'd exported a function declaration like this:
export function foo() {
}
...the "usual rules" mean you could use foo anywhere in your module code, because it's still hoisted. (Same for export var x;.)
(You can also test things like this with an up-to-date version of Chrome, which now supports modules. :-) )

Related

Javascript import all modules from a file as a global variables

In script1.js, I have the following exports:
export function test1() {
// do something
}
export function test2() {
// do something
}
I am importing script1.js into script2.js:
import * as functions from './script1.js';
functions.test1();
functions.test2();
I am wondering if there is a way to import all the modules from script1.js, and directly place them inside the global variables of script2.js. So I can directly access them with test1(), test2(), without the intermediate step of putting them in an object.
I know that we can do import {test1, test2} from './script1.js';, but if I have a lot of exports, then the deconstruction will be tedious.
In another word, what I am looking for is something equivalent of:
import * from './script1.js';
test1();
test2();
The above code block is hypothetical, and it does not work.
Given your current code, it's not possible. The whole point of modules is to avoid implicit global pollution. To do something like this, you'd have to explicitly assign the functions to the global object inside the module, eg, change:
export function test1() {
// do something
}
to
window.test1 = function test1() {
// do something
};
and then, when the module is imported, the functions will be available globally:
import './script1.js';
But this is an antipattern:
but if I have a lot of exports, then the desconstruction will be tedious.
It does require some boilerplate, but don't be afraid of it - in larger projects, having explicit dependency chains is a huge plus for maintainability. It also permits tree-shaking, which isn't possible for modules with side-effects only (like assigning to the global object).
you can also very simply auto generate the import , with a script like this:
import * as functions from './script1.js';
const function_names = Object.keys(functions).join(',')
console.log( function_names ) //output: test1,test2
your list is ready in your console!

Calling an exported function by a string value of the function name

This is a very simple example of what I am trying to achieve, basically I want to call a function by a string value of it's name, e.g. "hello" should call hello()
I have a helper.js file which contains an exported function e.g.
export function hello() {
console.log('is it me you`re looking for?');
}
I am importing this into another js file for usage
import {hello} from './helper';
I have tried using eval, window and new Function to call my function but no luck
//getting console error "hello is not defined"
eval('hello()');
var fn = window['hello()'];
fn();
var fn = new Function('hello()');
fn();
If I wrap the function like so, the eval fires the wrapper.
function helloWrapper() {
hello();
}
eval('helloWrapper()');
I just cant seem to fire the exported hello() function directly. I have around 10 functions I'll need to fire so having a wrapper for each seems a bit hacky and wondering if there is a way I can achieve this?
Any help would be greatly appreciated if anyone can point me in the right direction.
Thanks in advance
eval("hello()") should work just fine -- but it's not how you should do this. :-)
Instead, build an object containing the functions:
import {hello} from './helper'; // In some environments, these need the
import {groot} from './groot'; // .js on the filenames.
// ...
const functions = {hello, groot/*, ... */};
and then call them like this:
functions[name]();
Live example on plnkr.co
Generally, referring functions by their names is unsafe in client-side code - or any other that can be minified. The approach explained in the question will work only because hello isn't just function name but an import. Due to how ES modules work, import names will be preserved on minification.
In order for a function to be referred by its name, it should be object property. In case of imports there's already such object, it's module export:
import * as helper from './helper';
helper['hello']();
In case there are multiple modules where functions may originate from, there should be intermediate module that re-exports them.
export * from './helper';
export * from './another-helper';
All functions from underlying modules will be available as properties when it's imported as *:
import * as helper from './reexported-helpers';
helper['hello']();
helper['bye']();

Node.js issues with exporting functions

I have a few questions about the nature of exporting functions in NodeJS:
Firstly this is an acceptable way to export a function:
exports.bread = function bread() {
return 'bread: 2';
};
However, it is not possible (maybe?) to export a function using this method:
function pullData(pair) {
console.log(pair);
}
module.exports = pullData;
The only problem with this second method is that the function is not hoisted and limits its' use elsewhere?
Another method for exporting variables is to include the variables within an object and export that object. However, in this case, the functions within the module have a limited scope...
So is there any easy way to export declarative functions and use them, or is doing so not something I should strive to achieve?
Screenshots from project:
When you write module.exports = something you are exporting only one thing. So your code should look like this
var pullData = require('./getTicker')
pullData('TEST')
If you want to write it the way you have done so then you need to export it differently, as only part of the module.exports object.
You can do this by writing
exports.pullData = pullData in your getTicker file.
Then you can import it and use it like you did:
var trackData = require('./getTicker')
trackData.pullData('TEST')
Try putting pullData in curly brackets:
module.exports = {pullData}
and when you require it, do this:
const {pullData} = require("./getTicker");
Hope it'll work.

Javascript ES6 export const vs export let

Let's say I have a variable that I want to export. What's the difference between
export const a = 1;
vs
export let a = 1;
I understand the difference between const and let, but when you export them, what are the differences?
In ES6, imports are live read-only views on exported-values. As a result, when you do import a from "somemodule";, you cannot assign to a no matter how you declare a in the module.
However, since imported variables are live views, they do change according to the "raw" exported variable in exports. Consider the following code (borrowed from the reference article below):
//------ lib.js ------
export let counter = 3;
export function incCounter() {
counter++;
}
//------ main1.js ------
import { counter, incCounter } from './lib';
// The imported value `counter` is live
console.log(counter); // 3
incCounter();
console.log(counter); // 4
// The imported value can’t be changed
counter++; // TypeError
As you can see, the difference really lies in lib.js, not main1.js.
To summarize:
You cannot assign to import-ed variables, no matter how you declare the corresponding variables in the module.
The traditional let-vs-const semantics applies to the declared variable in the module.
If the variable is declared const, it cannot be reassigned or rebound in anywhere.
If the variable is declared let, it can only be reassigned in the module (but not the user). If it is changed, the import-ed variable changes accordingly.
Reference:
http://exploringjs.com/es6/ch_modules.html#leanpub-auto-in-es6-imports-are-live-read-only-views-on-exported-values
I think that once you've imported it, the behaviour is the same (in the place your variable will be used outside source file).
The only difference would be if you try to reassign it before the end of this very file.

Convert closure to es6 module

I'm using a javascript build environment that supports es6 modules (using es6-module-transpiler) so you can simply import stuff across different files.
Now I got a third party library that I'd like to be "importable".
The library populates its functionality like this:
(function () {/*...*/}).call(this);
Would it be safe to omit the closure and convert it to:
export default function () {/* ... */};
Or is there a better way?
Thanks in advance!
The original code you show invokes the anonymous function, which to make any sense must define a global variable, whereas the second code fragment you show merely exports the function, which is a different thing.
For purposes of discussion, let's assume the original code defines a global like this:
// my-third-party-module.js
(function() {
let myVar = 22;
window.MyThirdPartyModule = { log: function() { console.log(myVar); } };
}.call(this);
and you are using is as so:
// app.js
MyThirdPartyModule.log();
You could rewrite this as
// my-third-party-module.js
let myVar = 22;
export default { log: function() { console.log(myVar); } };
// app.js
import MyThirdPartyModule from `my-third-party-module';
MyThirdPartyModule.log();
Note that we have moved the variable myVar which was local to the anonymous function to the top module level.
However, depending on your preferences, rather than exporting a big object, which is sort of a pre-module mentality, you might want to export its APIs individually:
// my-third-party-module.js
let myVar = 22;
export function log { console.log(myVar); }
// app.js
import {log} from `my-third-party-module';
log();
or if you prefer
// app.js
import * as MyThirdPartyModule from `my-third-party-module';
MyThirdPartyModule.log();
However, all of these approaches assume you are able and willing to edit the source of the third party library. If that is not the case, you could write a little piece of glue code, such as
// my-third-party-module-interface.js
import 'my-third-party-module'; // This will run the module.
export default MyThirdPartyModule; // Export the global it defined.
// app.js
import MyThirdPartyModule from 'my-third-party-module-interface';
If you would prefer again to export individual APIs, you could extend the glue to re-export each of them:
// my-third-party-module-interface.js
import 'my-third-party-module'; // This will run the module.
const {log, otherAPI, ...} = MyThirdPartyModule;
export {log, otherAPI, ...};
// app.js
import {log} from 'my-third-party-module-interface';
The conversion of legacy dependencies is still an issue. And the horrible workflow they use makes things a lot harder, prefixing the actual code with browserify and webpack silliness.
So what to do? Existentially, the library is guaranteed only to deposit a global in window but by obscure and weird ways. And all slightly different.
So let the legacy simply do what it is supposed to do for you, but wrapped in a module so that you can import it rather than use a script tag:
https://medium.com/#backspaces/es6-modules-part-2-libs-wrap-em-up-8715e116d690

Categories

Resources