Using const for requiring a module - javascript

In one of my NodeJS application , I noticed the below code;
const { Function } = require('./modules/helpers.js')
Is this valid? Also any benefits of using const for the require ?

Yes, destructuring assignment is a valid syntax:
The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables.
({a, b} = {a: 10, b: 20});
console.log(a); // 10
console.log(b); // 20
See: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
EDIT:
As for the benefits, It is a syntax sugar in most of the case. It allows you to refer the import functions directly as Function instead of Helper.Function.
It can also reduce your bundle.js file size.

Making use of const has some big improvements for yourself. So you can't change your imported modules anymore. This imported modules is so called immutable, which is really good for some points. For more have a look over here: Short Introduction into immutable data structures
Edit: const doesn't really mean that a value isn't changeable anymore, but it means that the object at this point can't be reassigned. (Thanks to #Mark Stosberg for pointing that out again)
(simply the code is more easily to reason about and it is about good code style)
And the syntax is valid ES6 destructing syntax. Make sure that your module exports an variable called Function. For more have a look over here: MDN Destruction Syntax

Related

Why ECMAScript ES module import do not follow destructuring standard? [duplicate]

This question already has an answer here:
Relation between import and destructing es6 syntax?
(1 answer)
Closed 11 months ago.
In JavaScript I can rename and imported module this way
import { original_name as alias_name } from 'my_module'
Is there a good explanation for the need of as keyword and nod just follow the excellent destructuring standard?
Why not something like this:
import { original_name: alias_name } from 'my_module'
Just a curiosity always come to my mind
The answer is of course, they are different because they do different things, and only happen to have similarities in syntax.
But maybe there is a better reason why they were designed that way? I experimented with Node.JS modules in the following way:
// origin.js
export let specialNumber = 2;
setInterval(() => {
specialNumber = Math.random();
}, 400)
// importer.js
import { specialNumber as aliasAttempt } from './origin.js'
import * as StarImport from './origin.js'
let { specialNumber: destructuringAttempt } = StarImport;
setInterval(() => {
console.log(aliasAttempt, destructuringAttempt);
}, 400)
Here, destructuringAttempt will always give "2" (the value it got when it was destructured), whereas aliasAttempt will be keep getting changed. For example:
0.3600619094195876 2
0.33268826082163194 2
0.20684912705131553 2
0.8665522020482055 2
0.9349778920742413 2
It looks like destructuringAttempt copied by value during destructuring, whereas aliasAttempt keeps the reference to the let specialNumber variable.
(this behavior of destructuringAttempt is expected as let { specialNumber: destructuringAttempt } = StarImport; is just the same as let destructuringAttempt = StarImport.specialNumber; i.e. just copied the number)
So, maybe the reason was that, if the export is a non-const value, 'aliasing' gives a different result ("keep reference to the other variable") from typical destructuring behavior ("copy once"), therefore it's better to distinguish the syntaxes.
They do different things:
Destructuring is a form of property access, usually combined with a variable declaration like const, and possibly even a default initialiser
Importing a variable does declare an alias for a binding in the module scope
The important difference is that destructuring does run code (test object coercability, execute getters) while import declarations are fully declarative (setting up dependencies between modules, enabling cross-module hoisting even before the variables are initialised). This makes the latter statically analysable. Import aliases also have no concept of nested objects.
Both do allow "renaming", but they use different syntax for different things - it would've been too confusing otherwise. That their shorthand forms are similar to each other is mostly coincidental, caused by both using braces.

Is there any advantage to using Object.create(null) over a Map?

I've seen people use code that looks like
const STUFF_MAP = Object.create(null);
STUFF_MAP would like suggested only be used like a map, so I understand why using Object.create(null) is better than {} (removing the properties that could cause conflicts etc.), but is there any advantage to not just use
const STUFF_MAP = new Map();
When would I use each one? Does it have to do with being compiled to pre es6?
Does it have to do with being compiled to pre es6?
Yes, Object.create(null) is ES5 and won't need a polyfill for Map, if you need to support old browsers.
Apart from that, you should prefer the more modern Map which is also clearly indicates the purpose of a variable. You will need to access the collection using has/get/set methods, not in operator/bracket syntax/assignment. This can sometimes lead to code that isn't as concise, e.g. for incrementing a value you cannot use a compound assignment operator.
As for performance, there should not be much of a difference; if you care, do a benchmark for your particular situation.

How can I make a sub-function for a pre-existing data type? [duplicate]

I was working on an AJAX-enabled asp.net application.
I've just added some methods to Array.prototype like
Array.prototype.doSomething = function(){
...
}
This solution worked for me, being possible reuse code in a 'pretty' way.
But when I've tested it working with the entire page, I had problems..
We had some custom ajax extenders, and they started to behave as the unexpected: some controls displayed 'undefined' around its content or value.
What could be the cause for that? Am I missing something about modifing the prototype of standart objects?
Note: I'm pretty sure that the error begins when I modify the prototype for Array. It should be only compatible with IE.
While the potential for clashing with other bits o' code the override a function on a prototype is still a risk, if you want to do this with modern versions of JavaScript, you can use the Object.defineProperty method, e.g.
// functional sort
Object.defineProperty(Array.prototype, 'sortf', {
value: function(compare) { return [].concat(this).sort(compare); }
});
Modifying the built-in object prototypes is a bad idea in general, because it always has the potential to clash with code from other vendors or libraries that loads on the same page.
In the case of the Array object prototype, it is an especially bad idea, because it has the potential to interfere with any piece of code that iterates over the members of any array, for instance with for .. in.
To illustrate using an example (borrowed from here):
Array.prototype.foo = 1;
// somewhere deep in other javascript code...
var a = [1,2,3,4,5];
for (x in a){
// Now foo is a part of EVERY array and
// will show up here as a value of 'x'
}
Unfortunately, the existence of questionable code that does this has made it necessary to also avoid using plain for..in for array iteration, at least if you want maximum portability, just to guard against cases where some other nuisance code has modified the Array prototype. So you really need to do both: you should avoid plain for..in in case some n00b has modified the Array prototype, and you should avoid modifying the Array prototype so you don't mess up any code that uses plain for..in to iterate over arrays.
It would be better for you to create your own type of object constructor complete with doSomething function, rather than extending the built-in Array.
What about Object.defineProperty?
There now exists Object.defineProperty as a general way of extending object prototypes without the new properties being enumerable, though this still doesn't justify extending the built-in types, because even besides for..in there is still the potential for conflicts with other scripts. Consider someone using two Javascript frameworks that both try to extend the Array in a similar way and pick the same method name. Or, consider someone forking your code and then putting both the original and forked versions on the same page. Will the custom enhancements to the Array object still work?
This is the reality with Javascript, and why you should avoid modifying the prototypes of built-in types, even with Object.defineProperty. Define your own types with your own constructors.
There is a caution! Maybe you did that: fiddle demo
Let us say an array and a method foo which return first element:
var myArray = ["apple","ball","cat"];
foo(myArray) // <- 'apple'
function foo(array){
return array[0]
}
The above is okay because the functions are uplifted to the top during interpretation time.
But, this DOES NOT work: (Because the prototype is not defined)
myArray.foo() // <- 'undefined function foo'
Array.prototype.foo = function(){
return this[0]
}
For this to work, simply define prototypes at the top:
Array.prototype.foo = function(){
return this[0]
}
myArray.foo() // <- 'apple'
And YES! You can override prototypes!!! It is ALLOWED. You can even define your own own add method for Arrays.
You augmented generic types so to speak. You've probably overwritten some other lib's functionality and that's why it stopped working.
Suppose that some lib you're using extends Array with function Array.remove(). After the lib has loaded, you also add remove() to Array's prototype but with your own functionality. When lib will call your function it will probably work in a different way as expected and break it's execution... That's what's happening here.
Using Recursion
function forEachWithBreak(someArray, fn){
let breakFlag = false
function breakFn(){
breakFlag = true
}
function loop(indexIntoSomeArray){
if(!breakFlag && indexIntoSomeArray<someArray.length){
fn(someArray[indexIntoSomeArray],breakFn)
loop(indexIntoSomeArray+1)
}
}
loop(0)
}
Test 1 ... break is not called
forEachWithBreak(["a","b","c","d","e","f","g"], function(element, breakFn){
console.log(element)
})
Produces
a
b
c
d
e
f
g
Test 2 ... break is called after element c
forEachWithBreak(["a","b","c","d","e","f","g"], function(element, breakFn){
console.log(element)
if(element =="c"){breakFn()}
})
Produces
a
b
c
There are 2 problems (as mentioned above)
It's enumerable (i.e. will be seen in for .. in)
Potential clashes (js, yourself, third party, etc.)
To solve these 2 problems we will:
Use Object.defineProperty
Give a unique id for our methods
const arrayMethods = {
doSomething: "uuid() - a real function"
}
Object.defineProperty(Array.prototype, arrayMethods.doSomething, {
value() {
// Your code, log as an example
this.forEach(v => console.log(v))
}
})
const arr = [1, 2, 3]
arr[arrayMethods.doSomething]() // 1, 2, 3
The syntax is a bit weird but it's nice if you want to chain methods (just don't forget to return this):
arr
.map(x=>x+1)
[arrayMethods.log]()
.map(x=>x+1)
[arrayMethods.log]()
In general messing with the core javascript objects is a bad idea. You never know what any third party libraries might be expecting and changing the core objects in javascript changes them for everything.
If you use Prototype it's especially bad because prototype messes with the global scope as well and it's hard to tell if you are going to collide or not. Actually modifying core parts of any language is usually a bad idea even in javascript.
(lisp might be the small exception there)

Is it possible to import variables in JavaScript (node.js)?

I have variables in app.js:
var G = {};
module.exports = G;
var DATA = G.DATA = 'DATA';
var F1 = G.F1 = function(val)
{
return val;
};
In this manner, I can export variables under the object G, and at the same time, can access the variable directly writing DATA without G. prefix.
So far so good.
Now, I want to run a test for app.js in test.js:
var G = require('./app.js');
console.log(G.DATA); // -> DATA
This works, but I also want to access the variable directly writing DATA without G. prefix like console.log(DATA); // -> DATA
Surely, I could do like
var DATA = G.DATA; for every variables(property) export&required module G object, but obviously it's a tedious process to add every variable to the test file manually to correspond the G objects.
Is there any way to do this automatically?
So far, I'm pessmistic since
JS function encloses var in the own scope, so in theory there's no way to have a helper function to var for every object property.
Thanks.
PS. I would like to avoid any eval or VM of node solution. I have tried them in past, and too much problems.
I could assign a local variables for every property export&required module G object, but obviously it's a tedious process to add every variable to the test file manually to correspond the G objects.
No, that's how it is supposed to work. You - and only you - are in charge of what local variables exist in your module scope. No changes in the "export variables" of an included module should break your code.
Accessing properties on the imported module (with a self-chosen name) is the way to go. This is quite equivalent to Python's import app or import app as g.
If you want some particular properties as local variables, you will usually choose them manually, as in Python's from app import DATA, F1. In JS, you will need a multiple var statement like the one you've shown in your question. However, there is a syntax feature called destructuring assignment which will make this more fluid. You can use this in JavaScript 1.7+ (Gecko), CoffeeScript, or EcmaScript 6:
var {DATA, F1} = require("app.js");
Is there any way to do this automatically?
Yes and No. You should not do this, but you can - just like Python's frowned-upon from app import *. To cite what they say, which is equally true for JavaScript:
[It] introduces an unknown set of names into the interpreter, possibly
hiding some things you have already defined.
Note that in general the practice of importing * from a module or
package is frowned upon, since it often causes poorly readable code.
However, it is okay to use it to save typing in interactive sessions.
In JavaScript, you can[1] use the with-statement:
with (require("app.js")) {
…
}
[1]: Not in ES5.1 strict mode, though - which is recommended for optimisation

Is there a way to define symbolic constants in Javascript?

I searched if JavaScript offers a mean to define symbolic constants, but didn't find anything. Did I miss something ?
Is it a common practices to use const var instead ?
var const MAXIMUM_VALUE = 100;
Thanx.
const is not supported by IE, so if you want to support IE that is out of the question.
As far as I know, and the best way of doing this to keep it simple is to just have a naming convention for your constants like the ever-popular ALL UPPERCASE. There are some examples out there to force constants but they are not worth it for the most part. Alternatively, you could use a function:
function myConst() { return 'myValue'; }
This can of course still be overridden but I've seen it used.
Also see:
Are there constants in Javascript?
Is it possible to simulate constants in Javascript using closures?
Javascript: final / immutable global variables?
Yes. But you remove the var. const replaces var.
const MAXIMUM_VALUE = 100;
Object.defineProperty(window, 'CONSTANT_NAME', {value: CONSTANT_VALUE});
// usage
console.log(CONSTANT_NAME);
Object.defineProperty() creates a property with the following default attributes:
configurable true if and only if the type of this property descriptor may be changed and if the property may be deleted from the corresponding object.
Defaults to false.
enumerable true if and only if this property shows up during enumeration of the properties on the corresponding object. Defaults to false.
writable true if and only if the value associated with the property may be changed with an assignment operator. Defaults to false.
if the "constant" is an object you might additionally want to make it immutable by freezing it. obj =Object.freeze(obj). have in mind that child-property-objects are not automatically frozen.

Categories