In typescript I can import another module\namespace like so:
namespace Shapes2 {
import shapes = Shapes;
var bar = new shapes.Bar();
}
However, I can just as easily refer to the namespace directly.
namespace Shapes3{
var shapes = Shapes;
var bar = new shapes.Bar();
}
Is import doing anything useful?
When would I want to type import rather than var?
In that specific case, no it's not doing anything useful. That syntax is for creating aliases for namespaces. Your example would be more useful in a situation like this:
namespace Shapes2 {
import Rects = Shapes.Rectangles;
var bar = new Rects.Red();
// Instead of `var bar = new Shapes.Rectangles.Red()`
}
Basically, it's just a way of reducing the amount of typing you do. In a way, it's a substitution for using in C#. But how does this differ from var?
This is similar to using var, but also works on the type and namespace meanings of the imported symbol. Importantly, for values, import is a distinct reference from the original symbol, so changes to an aliased var will not be reflected in the original variable.
source
A good example of this can be found in the spec:
namespace A {
export interface X { s: string }
}
namespace B {
var A = 1;
import Y = A;
}
'Y' is a local alias for the non-instantiated namespace 'A'. If the declaration of 'A' is changed such that 'A' becomes an instantiated namespace, for example by including a variable declaration in 'A', the import statement in 'B' above would be an error because the expression 'A' doesn't reference the namespace instance of namespace 'A'.
When an import statement includes an export modifier, all meanings of the local alias are exported.
From the TypeScript Handbook
Another way that you can simplify working with of namespaces is to use import q = x.y.z to create shorter names for commonly-used objects. Not to be confused with the import x = require("name") syntax used to load modules, this syntax simply creates an alias for the specified symbol. You can use these sorts of imports (commonly referred to as aliases) for any kind of identifier, including objects created from module imports.
Related
My initial page load instantiates PageInit as follows.
<script>
"use strict";
let PageInit = null;
document.addEventListener("DOMContentLoaded", () => {
PageInit = new IPageInit();
});
</script>
I had to let PageInit=null in order to put that reference into the global name space to make it visible. I suspect that is wrong, because I can't imagine that every class that is instantiated has to be done so in global. (??) So, guidance on the right way to do this is appreciated also.
PageInit(), once it is created has a constructor that calls a class method, which in turns creates an instance of another class:
class IPageInit {
constructor() {
this.InitialiseComponents();
}
//Class Method
InitialiseComponents() {
this.PageContent = new IPageContent();
}
}
Coming from a C# background, I do not create an instance of a class with the class's exact name, as you see above. The class name is "IPageContent", and the instantiated name is just "PageContent". (Again, guidance on the right naming conventions is appreciated.)
PageContent(), when it is instantiated has a constructor that itself creates a property called "TrafficData".
class IPageContent {
constructor() {
this.TrafficData = "Paragraph 13.5";
}
}
Later, in "loose javascript" code on the page, a function tries to make a reference to TrafficData. I've tried two ways:
// page javascript
function LoadTrafficData {
let x = PageContent.TrafficData; // PageContent (itself) is undefined
let x = PageInit.TrafficData; // PageInit is valid object, but TrafficData is undefined
}
As you see, neither way works. I do not know enough about scope and visibility in instantiated JavaScript classes to figure out what is wrong and what to do about it. I am using plain vanilla JS - no frameworks, APIs, or Libraries.
How do I get LoadTrafficData() (a loose function, not a class method) to get a reference to TrafficData?
You are correct that global variables are generally a bad practice. Modern js uses imports to import classes into other classes. For example, you might have a PageService singleton class that creates an instance of your PageContent class and holds it in a class property. Other classes could import your PageService singleton to use its properties.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules
Your naming conventions are a bit unusual for JS as well:
Class names are normally capitalized, like PageContent, and instances are lowercase, like pageContent.
Class methods and functions should start with lowercase letters.
In typescript, you would prefix interfaces with an I, like IPageInterface, but you wouldn't normally prefix class names in regular javascript.
To debug your stuff, it's common to do console.log(myVariable) to inspect things. You can also insert a debugger; statement in your code to launch chrome's debugger at that line. To access your global var, you would do: PageInit.PageContent.TrafficData.
I am in the process of getting rid of most global variables in my program, but some will always be useful.
I have looked up answers to this several times and gave up finding an answer on my own - the supposed way to declare a global var with TS is like so:
declare var x: string;
which would translate to - global.x = 'foo';
but this declaration is not getting rid of the compilations errors or IDE warnings in Webstorm.
What is the best way to declare global vars in my program? I assume the best way to do it would involve a .d.ts file.
Here is the type of warning I see:
Not sure if this is the best way to do it:
in my file in my project called suman.d.ts, I have:
import Global = NodeJS.Global;
interface SumanGlobal extends Global {
_writeTestError: Function,
sumanRuntimeErrors: Array<Error | string>,
sumanOpts: Object,
sumanUncaughtExceptionTriggered: boolean
}
declare var global: SumanGlobal;
seems to work for the moment
As I understand it (see section 16.3.2.1), ES6 allows different syntaxes for function / class export operands. The difference refers to whether the exported function needs to be interpreted at import as a function declaration, in which case you write: export default function () {} // (a) or as a function expression: export default (function () {}); // (b).
As a possible related sidenote: I read that imports are hoisted, but I'm not really sure what that means in this context.
Taking the case of this example:
import foo from 'my_module'; // (c)
As I understand it, the above statement will save my exported function in a foo variable. Is that variable hoisted, or what is, and when?
Most importantly, what is the difference (in terms of setting foo) when my_module exports the function using (a) and when it exports it using (b)?
Your question is a bit convoluted but I'll try my best to explain everything.
Let's first establish how modules work in general. A module has a set of exported names, each of which refer to a local variable in that module. The name of the export does not need to be the same as that of the local binding. One of the exported names can be default, for which there is special syntax (both in exporting and importing) dedicated for the case that a module only exports a single thing.
I read that imports are hoisted, but I'm not really sure what that means in this context:
import { foo } from 'my_module';
Yes, import declarations are hoisted. Similarly to a var or function (and actually like every other declaration) the identifier foo is available right from the beginning, before any statements in the module are executed. In fact the binding is even created before those of declared variables.
The difference is how they are initialised:
vars are initialised with undefined
functions and function*s are initialised with the function object
let, const and classes are left uninitialised
imported bindings are not even really initialised, they are created as a pointer to the local variable that the exported name refers to in the imported module
imported modules (import * as …) are initialised with a module object (whose properties are such pointers as well)
When is foo set to refer to my exported function?
The short answer: before everything else.
The long answer: it's not really set. It's a reference to the local variable in the imported module that you expect to hold the function. The local variable might change when it's not const - but we usually don't expect that of course. And normally it does contain that function already, because the imported module is completely evaluated before the module(s) that import it are. So if you fear there's a problem with var functionName = function() {} vs function functionName() {} you may be relieved - there is not.
Now back to your title question:
What is the difference between exporting a function expression and a function declaration in a ES6 module?
Nothing special, the two aspects actually don't have much to do with each other:
export declarations link an export name to a local variable in the module scope
All variables in the module scope are hoisted, as usual
function declarations are initialised differently than variable declarations with an assignment of a function expression, as usual
Of course, there still are no good reasons not to use the more declarative function declarations everywhere; this is not different in ES6 modules than before. If at all, there might even be less reasons to use function expressions, as everything is covered by declarations:
/* for named exports */
export function foo() {…}
// or
function foo() {…}
export {foo as foo}
/* for default exports */
export default function foo() {…}
// or
function foo() {…}
export {foo as default}
// or
function foo() {…}
export default foo;
// or
export default function() {…}
Ok, the last two default export declarations are actually a bit different than the first two. The local identifier that is linked to the exported name default is not foo, but *default* - it cannot be reassigned. This makes sense in the last case (where there is no name foo), but in the second-to-last case you should notice that foo is really just a local alias, not the exported variable itself. I would recommend against using this pattern.
Oh, and before you ask: Yes, that last default export really is a function declaration as well, not an expression. An anonymous function declaration. That's new with ES6 :-)
So what exactly is the difference between export default function () {} and export default (function () {});
They are pretty much the same for every purpose. They're anonymous functions, with a .name property "default", that are held by that special *default* binding to to which the exported name default points to for anonymous export values.
Their only difference is hoisting - the declaration will get its function instantiated at the top of the module, the expression will only be evaluated once the execution of module code reaches the statement. However, given that there is no variable with an accessible name for them, this behavior is not observable except for one very odd special case: a module that imports itself. Um, yeah.
import def from "myself";
def(); // works and logs the message
export default function() {
console.log("I did it!");
}
import def from "myself";
def(); // throws a TypeError about `def` not being a function
export default (function() {
console.log("I tried!");
});
You really shouldn't do either of these things anyway. If you want to use an exported function in your module, give it a name in its declaration.
In that case, why have both syntaxes?
Happens. It's allowed by the spec because it doesn't make extra exceptions to prohibit certain nonsensical things. It is not intended to be used. In this case the spec even explicitly disallows function and class expressions in export default statements and treats them as declarations instead. By using the grouping operator, you found a loophole. Well done. Don't abuse it.
What is the difference between
var module = (function(){
return {}
})()
and
(function(context){
var module = {}
context.module = module;
})(this)
A property of this is not equivalent to a variable. In the global scope (i.e. where this references window), they are similiar. Yet, for example they will have a different behavior when you try to delete them:
> this.module = {};
> delete this.module
true
> var module = {};
// cant be deleted
Apart from that, both snippets create an empty object, wrapped inside a closure where you could define local (private) variables/functions etc. In your second function the object is also assigned to the local variable module, but that could be done in the first one as well.
#Eric: Your approach, using the new operator, is similiar to the first one regarding the variable. However, it will create an instance of that anonymous function instead of returning a plain object. It will inherit properties from a custom prototype, so for example module.constructor will then point to the anonymous function (which cannot be garbage collected, but e.g. even reused to create a clone). I would not recommend to use this.
Top one is revealing module pattern. It lets you define private functions (as much as you can in javascript) and choose which ones are made public via the return call.
var module = (function(){
function foo() {}; // Public, since it's returned
function bar() {}; // Private, since it is not returned
return {
foo: foo
}
})();
The bottom one, as far as I can tell, just assigns an object literal to another object's namespace. It's probably the start of a singelton pattern.
(function(context){
var module = {};
context.module = module;
}(this)
The module could actually be defined with the revealing module pattern, hard to say since in your example it's just an object literal.
If so, what is the syntax for such a declaration?
Javascript doesn't really have the notion of a named constant, or an immutable property of an object. (Note that I'm not talking about ES5 here.)
You can declare globals with a simple var declaration in the global scope, like outside any function in a script included by a web page:
<script>
var EXACTLY_ONE = 1;
Then your code can use that constant of course, though it's not really "constant" because the value can be changed (the property updated, in other words).
edit — this is an ancient answer to an ancient question. In 2019, there's the const declaration that's supported just about everywhere. However note that like let, const scoping is different from var scoping.
As "Pointy" so carefully notes, ECMAscript has no such feature. However, JavaScript does:
const a = 7;
document.writeln("a is " + a + ".");
Of course, if you're writing code to put on the web to run in web browsers, this might not help you much. :-)
Everything is global unless declared with the var keyword.
There are no constants either. You can simply declare them without the var keyword.
If you want to ensure global scope you can throw it into the window object:
window.GLOBAL_CONSTANT = "value";
You can do this from within any scope. Constants can then be declared inside functions or closures, though I wouldn't recommend that.
If you only care about supporting newer browsers (or are using a transpiler such as Babel to support older browsers) you can do the following:
Create a settings.js file with whatever constants you want and export them:
export const FRUIT = "kiwi";
export const VEGETABLE = "carrot";
In files that you want to use them you could then import them as follows:
import * as Settings from './settings.js'
Then to use the constants do something like this:
console.log("The unchangeable fruit is " + Settings.FRUIT);
This is a much cleaner approach than trying to implement a global constant, especially when you have multiple JavaScript files that you want to use the constants in.
You could do it with getters and setters like so:
Object.defineProperty(window, 'TAU', {
get: function(){return Math.PI*2;}
});
If you want a general function to do this:
function define(name, value){
Object.defineProperty(window, name, {
get: function(){return value;},
set: function(){throw(name+' is a constant and cannot be redeclared.');},
});
}
// Example use
define('TAU', Math.PI*2);
If you want to make sure the value cannot change use a function.
So, instead of:
var Const_X=12
use:
function Const_X() {
return 12;
}
The direct answer to the question is No. It would really help though if ECMA/JS made a way to easily do functional programming. A workable hack I use to get around this is to declare a const in the global scope and use a wrapper function see example below:
:)
global_var = 3; //This can change say inside a function etc. but once you decide to make
//this global variable into a constant by calling on a function
const make_variable_constant = function(variable)
{
const constant = variable;
return constant;
}
const const_global = make_variable_constant(global_var);
:)
Way back when object oriented programming was the hype a kid in my class told the C instructor that C isn't object oriented to which the instructor said he's done object oriented programming in C before Java and C++ were even conceived. Likewise you can do functional programming in Javascript but its much harder. Its like doing Object-oriented programming in C when its easier to do it in C++.
For the record.
// ES6+ code:
const CONSTGLOBAL1=200; // it is a constant global
function somef() {
document.write(CONSTGLOBAL1); // CONSTGLOBAL1 is defined (because it's global)
const CONSTLOCAL=200; // it's a local constant
document.write(CONSTLOCAL); // CONSTLOCAL is defined
}
somef();
document.write(CONSTLOCAL); // CONSTLOCALis NOT defined.
So, if the constant is defined inside {} then it's local, otherwise, it's global.
Similar to kojow7's answer, but instead of using grabbing all named exports I like to use one named export e.g. Constants and then declare my constants like this:
Create a Constants.js file with declaring your constants like this and export Constants:
// Constants.js
export const Constants = {
FRUIT: "kiwi",
VEGETABLE: "carrot",
};
Make a named import in the files you need a constant:
import { Constants } from './Constants';
Then use the constants as follows:
console.log("The unchangeable fruit is " + Constants.FRUIT);
There seems to be no downfall to use the one over the other option, but what I like personally is that I just name the file as I want to import it import { Constants } from './Constants'; and not always think about how I call it when grabbing all named exports import * as Constants from './Constants'. So in the second case I might want to look in another file where I imported already the constants and look how I named the import in case of consistency. Have a look also here for the different export/import possibilities.
If you're not planning to change the value of any object properties, you can use Object.freeze():
window.globalConst = Object.freeze( { x: 1, y: true } );
The following demonstrates the difference between const and Object.freeze():
const x = Object.freeze({
a: 1,
b: 2
});
x.a = 3;
// x.a is still = 1
console.log("x.a = ", x.a);
const y = {
a: 1,
b: 2
};
y.a = 3;
// y.a has been changed to 3
console.log("y.a = ", y.a);