The title says everything I want to ask. I cannot understand what are the key differences in using window and const {}.
I tried both and the result is the same. Can you help me understanding this?
P.S. I am using Laravel and it is using window global variable. Some libraries show method with const {}.
The difference is that window.XXX = require(YYY) assigns the object returned from require(YYY) call to XXX variable on the window object. But const {XXX} = require(YYY) uses destructuring assignment to unpack the property XXX from the object returned by require(YYY). So calling const {XXX} = require(YYY) in window scope will be equal to window.XXX = require(YYY).XXX. Now to the question which to use? the answer is which ever you need in the specific case.
require may be old method - it depends on your enviroment.
const foo = require('bar');
//is almost the same as
imrport foo from 'bar';
Import method have more posibilities eg:
//file foo.js
export const myStr = 'lol';
export default (x)=>x**4;
export * as lol from './someFile';
Other file:
import {myStr, lol}, defaultExported from './foo';
The idea is to encapsulate variables to not accidentaly reassign in two places same variable, so window may be not needed anymore. If you need some variable/const you import it in other file.
If you need backward compatibility in your enviroment, you use babel (here is online version) https://babeljs.io/repl/
You know laravel, so beware of some differences in JavaScript const:
const foo = 1;
foo = 2; //error
const arr = [1];
arr[0]++; //[2]
arr[1] = 'lol'; //no error
const obj = {};
obj.lol = 'man'; //it works
Related
Is there an option to get a reference to the whole script variables?
lets assume this code:
const a=n=>n+1,
b={};
let c=3
I wonder if I can access all variables by one reference, like this vars:
vars.b //{}
vars[varName]
so that I'll be able to pass it to other sub modules easily instead of creating a manualy associative array with the variables of the script
It is possible only to some limit.
There is globalThis variable acting as a container for all top-level variables.
And also in every function arguments variable is available holding everything passed to function in the current call.
I'm not aware of anything similar for function-/block-scope variables
I think you can assign those variables to a JSON object and then export the JSON object as follows so that you can reference all the variables in other file.
// scripts.js file
let a = n => n+1;
let b = {};
let c = 3;
module.exports = { a, b, c };
// index.js file
const scripts = require('./scripts');
console.log(scripts.a(4));
console.log(scripts.b);
console.log(scripts.c);
No, there's no way to programatically get access to the environment record of a given function/scope/closure. To do something like this, the best way would be to define the variables as part of an object or Map in the first place. Instead of
const a=n=>n+1,
b={};
let c=3
do
const theNamespace = {
a: n=>n+1,
b: {},
c: 3
};
and pass theNamespace around.
look at this example:
const a = 5
module.exports.a = a;
let b = "foo"
module.exporta.b = b
if we export this variables . in everywhere a variable is const and b variable is let .what about this example :
module.exports.c = "bar"
what is this? a var type? let? const? I mean javascript engine treat this to what? I am getting wrong definition or behavior of javascript or this is a correct question that came to my mind?
const and let are for defining variables. Things in module.exports are properties of an object (that object being module.exports), and so they are controlled by their property descriptors. Whether or not the value is mutable is controlled by the writable descriptor field. It no longer has a scope of its own, it can be accessed wherever its parent can. You can't really think of them like a let or const.
Since in Javascript, arguments are passed by value, in this:
let b = "foo"
module.exports.b = b
After this code is executed, module.exports.b has nothing to do with the variable b. It's not a let, or a const it's just a property of module.exports. You could change the value of b and it would have no effect on module.exports.b.
When you're doing module.exports.a = 'a', you're not exporting a variable itself, you're exporting a binding.
Then if when importing you assigng it to const like const {a} = require('./a'), it will be const, if you import it assigning to let {a} = require('./a'), it will be let.
I've been looking into code inside Facebook's react project to learn more about JavaScript. In particular, I saw syntax that looks like this
const pureComponentPrototype = (PureComponent.prototype = new ComponentDummy());
I've never encountered code like this before. What does it mean when PureComponent.prototype = new ComponentDummy() is wrapped inside parenthesis?
What is the name for this type of syntax? Thanks in advance.
The parenthesis are just for readability. all you are doing is
a = b = 5;
Actually the assignment operator returns the left side value.
e.g. : function test() { let b; return b = 5; } test(); // 5
So that should be it. Note that if we don't declare 'b' variable with let/var/const it will become a global variable. But thats one different discussion.
Let's say we have a function that looks like this:
const fn = () => x;
This function should return the value of x where x is available in the global scope. Initially this is undefined but if we define x:
const x = 42;
Then we can expect fn to return 42.
Now let's say we wanted to render fn as a string. In JavaScript we have toString for this purpose. However let's also say we wanted to eventually execute fn in a new context (i.e. using eval) and so any global references it uses should be internalized either before or during our call to toString.
How can we make x a local variable whose value reflects the global value of x at the time we convert fn to a string? Assume we cannot know x is named x. That said we can assume the variables are contained in the same module.
If you want lock certain variables while converting function to string, you have to pass that variables along the stringified function.
It could be implemented like this (written with types -- typescript notation)
const prepareForEval =
(fn: Function, variablesToLock: { [varName: string]: any }): string => {
const stringifiedVariables = Object.keys(variablesToLock)
.map(varName => `var ${varName}=${JSON.stringify(variablesToLock[varName])};`);
return stringifiedVariables.join("") + fn.toString();
}
Then use it like this
const stringifiedFunction = prepareForEval(someFunction, { x: x, y: y })
// you can even simplify declaration of object, in ES6 you simply write
const stringifiedFunction = prepareForEval(someFunction, { x, y })
// all variables you write into curly braces will be stringified
// and therefor "locked" in time you call prepareForEval()
Any eval will declare stringified variables and funtion in place, where it was executed. This could be problem, you might redeclare some variable to new, unknown value, you must know the name of stringified function to be able to call it or it can produce an error, if you redeclare already declared const variable.
To overcome that issue, you shall implement the stringified function as immediatelly executed anonymous function with its own scope, like
const prepareForEval =
(fn: Function, variablesToLock: { [varName: string]: any }): string => {
const stringifiedVariables = Object.keys(variablesToLock)
.map(varName => `var ${varName}=${JSON.stringify(variablesToLock[varName])};`);
return `
var ${fn.name} = (function() {
${stringifiedVariables.join("")}
return ${fn.toString()};
)();
`;
}
this modification will declare function and variables in separate scope and then it will assign that function to fn.name constant. The variables will not polute the scope, where you eval, it will just declare new fn.name variable and this new variable will be set to deserialized function.
We cannot know x is named x. This is the central piece of this puzzle and is therefore bolded in the original question. While it would be nice if we had a simpler solution, it does seem a proper answer here comes down to implementing some kind of parser or AST traversal.
Why is this necessary? While we can make the assumption that x lives in a module as a global (it's necessarily shared between functions), we cannot assume it has a known name. So then we need some way of extracting x (or all globals really) from our module and then providing it as context when we eventually eval.
N.B.: providing known variables as context is trivial. Several answers here seem to assume that's a difficult problem but in fact it's quite easy to do with eval; simply prepend the context as a string.
So then what's the correct answer here? If we were to use an AST (Acorn may be a viable starting point, for instance) we could examine the module and programmatically extract all the globals therein. This includes x or any other variable that might be shared between our functions; we can even inspect the functions to determine which variables are necessary for their execution.
Again the hope in asking this question originally was to distill a simpler solution or uncover prior art that might be adapted to fit our needs. Ultimately my answer and the answer I'm accepting comes down to the nontrivial task of parsing and extracting globals from a JavaScript module; there doesn't appear to be a simple way. I think this is a fair answer if not a practical one for us to implement today. (We will however address this later as our project grows.)
You can use OR operator || to concatenate current value of x to fn.toString() call
const fn = () => x;
const x = 42;
const _fn = `${fn.toString()} || ${x}`;
console.log(_fn, eval(_fn)());
Global variables can be made local (private) with closures. w3Schools
function myFunction() {
var a = 4;
return a * a;
}
Thanks to guest271314, I now see what you want.
This is his code, just little improved:
const stringifiedFn = `
(function() {
const _a = (${fn.toString()})();
return _a !== undefined ? _a : ${JSON.stringify(fn())};
})();
`;
this code will execute fn in context, where you eval, and if fn in that context returns undefined, it returns the output of fn in context, where it was stringified.
All credit goes to guest271314
do you mean this? only answer can post code, so I use answer
var x = 42
function fn() {
return x
}
(() => {
var x = 56
var localFn = eval('"use strict";(' + fn.toString()+')')
console.log(localFn)
console.log(localFn())
})()
why rename to localFn, if you use var fn=xx in this scope the outer fn never exists!
in nodejs? refer nodejs vm
passing context? you can not save js context unless you maintain your own scope like angularjs
If you're already "going there" by using eval() to execute fn() in the new context, then why not define the function itself using eval()?
eval('const fn = () => ' + x + ';')
Is there anyway to access ES6 constant by variable?
For ex.
const OPEN_TAB = 0;
const CLOSE_TAB = 1;
let action = 'OPEN';
console.log(window[`${action}_TAB`]); <-- something like that
No there is not (*). const declarations do not become properties of the global object.
You need to find another solution, such as creating an object and freeze it (to make it immutable):
const TAB = Object.freeze({
OPEN: 0,
CLOSE: 1,
});
console.log(TAB[action]);
I'd argue that relying on global variables (i.e. var) becoming properties of the global object is bad design anyway. If you want to look something up by name you really should have something like a map or a record (as shown above).
*: Well, you could use eval...
For the current code you have, you can use eval (But take care!), it should be like this:
const OPEN_TAB = 0;
const CLOSE_TAB = 1;
let action = 'OPEN';
console.log( eval (action+'_TAB') );
The other way is to assume a new object to the const, then you can access the const easily like the common way you can access to JavaScript objects:
const TAB = {
OPEN:0,
CLOSE:1
};
let action = 'OPEN';
console.log(TAB[action]);