Nested Function from another file does not access variable inside a function - javascript

I want to access local variables from a function inside a file using a nested function imported from another file, but when I try to access it, it displays undefined instead.
File 1:
import { getFirstName } from './getfirstname'
let name = { "fullname" : "John Doe" }
export class Class1 extends React.Component {
getName = (x) => {
var y = x.fullname
getFirstName(y)
}
}
getName(name);
File 2 (getfirstname.js) :
export const getFirstName = (z) => {
var fname = z.split(/\|/).map(s => s .split (/\s+/) [0])
console.log(fname)
}
How can I make sure using getName(name) returns John instead of undefined?
Edit: this working example should be more relevant to the question: https://codepen.io/marwann/pen/VwvRWrr

There are several problems with your code as posted:
Your Class1 extends React.Component for no apparent reason
You define getName as a instance method of Class1 but then try to call it directly, instead of as a property on an instance of Class1
You speak of "returning" but none of your code here returns anything-- it only logs to the console.
Ultimately, I don't think your issue is at all related to importing, and I suspect it is throwing an error when you try to call getName which does not exist in scope.
If we rewrite it with those things fixed, we should be able log a result:
const getFirstName = (z) => {
var fname = z.split(/\|/).map(s => s .split (/\s+/) [0])
return fname
}
let name = { "fullname" : "John Doe" }
class Class1 {
getName = (x) => {
var y = x.fullname;
return getFirstName(y);
}
}
const instance = new Class1();
const fname = instance.getName(name);
console.log(fname);
Note that I've created an instance of your class and called getName from that instance. I've additionally updated both getName and getFirstName to actually return a value.
A few other items to consider:
Nothing about your class as currently exists leverages the benefits you get from organizing your code into a class. It might be worth considering whether or not it is actually necessary.
I would recommend against mixing var with let and const. If you are working in an environment that allows you to leverage let/const, you can just replace any var with a let if it must be reassigned and a const if it will never be reassigned.

Related

export a variable inside a function to be used in other modules

I'm quite new to programming. I have spend last 3 days trying to figure this out. So any help really appreciate it.
I have access to clientID inside a for loop. (Please look at the last line in the code below). There is only one ClientID which I'm successfully able to print.
I want this client ID to be exported from this module so that I can use it in other modules.
import { Configurations } from './models';
type MethodNames = 'init' | 'event';
export const DEFAULT_NAME = '_hw';
interface LoaderObject {
q: Array<[MethodNames, {}]>;
}
export default (
win: Window,
defaultConfig: Configurations,
scriptElement: Element | null,
render: (element: HTMLElement, config: Configurations) => void
) => {
const instanceName =
scriptElement?.attributes.getNamedItem('id')?.value ?? DEFAULT_NAME;
const loaderObject: LoaderObject = win[instanceName];
if (!loaderObject || !loaderObject.q) {
throw new Error(
`Widget didn't find LoaderObject`);
}
if (win[`loaded-${instanceName}`]) {
throw new Error(
`Widget already loaded`)
);
}
let targetElement: HTMLElement;
for (let i = 0; i < loaderObject.q.length; i++) {
const item = loaderObject.q[i];
const methodName = item[0];
console.log(methodName);
if (i === 0 && methodName !== 'init') {
throw new Error(
`Failed to start Widget`);
} else if (i !== 0 && methodName === 'init') {
continue;
}
const valueObject = Object.assign(defaultConfig, item[1]);
const clientID = valueObject.clientID
console.log("ClientID", clientID)
}
//rest of the code....
I have also tried this. defined a variable clientID outside the for loop and then storing value from inside the for loop. But on printing, I'm getting undefined
var clientID;
console.log("....last Client ID", clientID)
const valueObject = Object.assign(defaultConfig, item[1]);
clientID = valueObject.clientID
Your issue is about your variables' scopes. Let's start with a simpler version, without for loop:
default export (a: object) => {
const variableToExport = a;
}
The reason why you can't directly access variableToExport is that it is defined inside the function, and not outside. To deal with it, you have 2 solutions:
1. Assign to a variable in the outer scope.
The code would look like:
/!\ Read the text below before using this snipplet /!\
export let variableToExport;
default export (a: object) => {
variableToExport = a;
}
Here, you're strictly speaking exporting the variable. Since it's defined outside the function, you can access it outside the function and thus, you can export it. HOWEVER, IT COULD BE A MISTAKE. If you call twice the exported function with different values for a, the variable variableToExport would only have the value corresponding to the second call, and not the first. If the value of variableToExport should not depend on a, it could be OK, but otherwise it seems risky.
2. Returning the value
Since your function would be called to get the variableToExport, you could return it:
default export (a: object) => {
const variableToExport = a;
return variableToExport;
}
In case you have multiple things to return, you can build an object to return them all:
default export (a: object) => {
const retValue = {
"variableToExport": a,
... other variables to return
}
return retValue;
}
Then, you can access it from another module (with or without a destructuring assignment):
import foo from 'path/to/module'
const { variableToExport, otherVariable } = foo(a);
This second way is safer than using a "global" variable, as the variableToExport can't have a value that correspond to another call to the function.
Now, for the case of your variable in the for loop, you have a similar issue: you can't access to the variable outside the for loop:
default export (bar: array) => {
for (const elem of bar) {
const clientID = elem.clientID;
}
return clientID; // Nope, clientID does not exist here
}
To deal with that, the first option works:
default export (bar: array) => {
let clientID; // Not const, because it will change
for (const elem of bar) {
clientID = elem.clientID;
}
return clientID;
}
This will thus return the last clientID (and since you said you have only one clientID, it should be ok), but it would be a little better of you could get the value of clientID outside the loop, except if you intend on exporting only the last value of clientID.
I hope that, even though you might not understand everything, you understand how to export the client ID you want to export, and that the key words I gave you allows you to easily find what you might need on the internet more easily than these 3 last days. Ask me if anything isn't clear enough, I'll answer when I'll have time
I think your problem is about your variable's scope. const is block-scoped so everything about clientID variable happens inside the for loop and does not affect outside. I guess you can use var or let up to your purpose. This is a quite explanatory article about difference between var, let, and const: https://www.freecodecamp.org/news/var-let-and-const-whats-the-difference/
MDN Document on const: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
I guess the way you can access the variable is by creating a let variable outside the loop then assign it a value in the loop, or create an array outside the loop and push values into it inside the loop, that way you can have access to the variable outside the loop's scope.

Console.log from a class' function

I want to test if my function inside my class returns the given sentence. But if I try to test using console.log, it returns ReferenceError: rev is not defined. What am I doing wrong?
class store {
constructor(revenue, workers) {
this.revenue = revenue;
this.workers = workers;
}
}
class storeManager extends store {
constructor(name) {
super(revenue, workers);
this.name = name;
}
rev() {
return "The stores revenue is" + this.revenue;
}
hiredWorkers() {
return "The store has" + this.revenue + "workers";
}
};
console.log(rev())
I'm a fairly new programmer, so bear with me if this is a stupid question.
The entire point of a class is to provide a template to bundle up functionality into a self-contained object and not have globals for everything.
rev is a method that appears on instances of the class. It isn't a global.
You have to create an instance of the class:
const myInstance = new StoreManager("some value for name");
(Note that this is going to fail because your constructor calls super() and tried to pass the values of variables which don't exist in the constructor method).
… and then call the method on that:
const result = myInstance.rev();

How to access variable key and use it as a variable in another function?

I'm sorry about the title I'm not sure what is the name of the issue I'm trying to solve.
Assume I have the following class with a function
{
printInfo(age){
console.log(name)
console.log(age)
}
}
From another page I want to call the class like this:
someClass.Mike.printInfo(21), and the function would print Mike and 21. Of course, the name Mike is variable so it can be anything.
Is there a way to accomplish that? Maybe something special in the constructor of the class? some JSON object keys manipulations?
Thank you.
Assuming you have stored the Names somewhere for example:
const names = ['Mike', 'Dave'];
you could access the function, if it is indeed stored in the regarding objects with dynamic properties like this:
names.forEach(name => {
someClass[name].printInfo(21);
})
If that is not what you need you should try to write your question a little bit more detailed.
The statement from another page is also a little bit confusing, if the class is not defined on the page than you cannot access it.
You'll need to pass any variables being used. You can do so by separating them:
printInfo(name, age)
To use it, you'd call the method like so:
SomeClass.printInfo("Mike", 21);
Create an instance for each person and pass the name in the constructor then call printInfo() from an instance to get the name and age :
class SomeClass {
constructor(name, age) {
this.name = name;
this.age = age;
}
printInfo(age){
console.log(this.name)
console.log(age || this.age)
}
}
const mike = new SomeClass('Mike');
mike.printInfo(21);
const jean = new SomeClass('Jean', 17);
jean.printInfo();
Or you can get your result using Objects:
const Mike = {
printInfo: (age) => { console.log('Mike'); console.log(age) }
};
const Jean = {
printInfo: (age) => { console.log('Jean'); console.log(age) }
};
const someClass = {
Mike,
Jean
};
someClass.Mike.printInfo(21);
someClass.Jean.printInfo(17);
// Or:
// let name = 'Mike';
// someClass[name].printInfo(21);
// name = 'Jean';
// someClass[name].printInfo(17);
Or even better:
const constructObject = (name) => ({
printInfo: (age) => { console.log(name); console.log(age) }
});
const someClass = {
Mike: constructObject('Mike'),
Jean: constructObject('Jean')
};
someClass.Mike.printInfo(21);
someClass.Jean.printInfo(17);
// Or:
// let name = 'Mike';
// someClass[name].printInfo(21);
// name = 'Jean';
// someClass[name].printInfo(17);

Dynamically updating exports Nodejs

I have this object that is being exported and imported by other files. Initially, the object is empty but during an event change ( a button clicked), the object is filled with keys and values but still remains empty in the files that imported it. How can I dynamically update an object and then export it with it's new values.
The code looks something like this:
firstFile.js
const anObject = {};
function clicked() {
anObject.firstName = "John";
anObject.lastName = "Doe" ;
}
module.exports = anObject;
secondFile.js
const importedObject = require("./firstFile");
console.log(importedObject) // always returns an empty object
You have to export and call the clicked function. Otherwise you are never actually updating that object.
For example.
firstFile.js
const anObject = {};
function clicked() {
anObject.firstName = "John";
anObject.lastName = "Doe" ;
}
module.exports = anObject;
module.exports.clicked = clicked;
secondFile.js
const importedObject = require("./firstFile");
console.log(importedObject.firstName) //undefined
importedObject.clicked()
console.log(importedObject.firstName) //John
Edit
After discussing further with the OP this is an Electron application. The code above works in Node.js. Electron might have a different setup and require extra steps to make this work.

Richembed not working [duplicate]

I am defining an object like this:
function Project(Attributes, ProjectWidth, ProjectHeight) {
this.ProjectHeight = ProjectHeight;
this.ProjectWidth = ProjectWidth;
this.ProjectScale = this.GetProjectScale();
this.Attributes = Attributes;
this.currentLayout = '';
this.CreateLayoutArray = function()
{....}
}
I then try to create an instance like this:
var newProj = new Project(a,b,c);
but this exception is thrown:
Project is not a constructor
What could be wrong? I googled around a lot, but I still can't figure out what I am doing wrong.
The code as posted in the question cannot generate that error, because Project is not a user-defined function / valid constructor.
function x(a,b,c){}
new x(1,2,3); // produces no errors
You've probably done something like this:
function Project(a,b,c) {}
Project = {}; // or possibly Project = new Project
new Project(1,2,3); // -> TypeError: Project is not a constructor
Variable declarations using var are hoisted and thus always evaluated before the rest of the code. So, this can also be causing issues:
function Project(){}
function localTest() {
new Project(1,2,3); // `Project` points to the local variable,
// not the global constructor!
//...some noise, causing you to forget that the `Project` constructor was used
var Project = 1; // Evaluated first
}
An additional cause of this can be ES2015 arrow functions. They cannot be used as constructors.
const f = () => {};
new f(); // This throws "f is not a constructor"
For me it was the differences between import and require on ES6.
E.g.
processor.js
class Processor {
}
export default Processor
index.js
const Processor = require('./processor');
const processor = new Processor() //fails with the error
import Processor from './processor'
const processor = new Processor() // succeed
I've googled around also and found this solution:
You have a variable Project somewhere that is not a function. Then the new operator will complain about it. Try console.log(Project) at the place where you would have used it as a construcotr, and you will find it.
For my project, the problem turned out to be a circular reference created by the require() calls:
y.js:
var x = require("./x.js");
var y = function() { console.log("result is " + x(); }
module.exports = y;
x.js:
var y = require("./y.js");
var my_y = new y(); // <- TypeError: y is not a constructor
var x = function() { console.log("result is " + my_y; }
module.exports = x;
The reason is that when it is attempting to initialize y, it creates a temporary "y" object (not class, object!) in the dependency system that is somehow not yet a constructor. Then, when x.js is finished being defined, it can continue making y a constructor. Only, x.js has an error in it where it tries to use the non-constructor y.
I have a class in one file that I'm importing into a test file:
//Vec.js
class Vec {
}
module.exports.Vec = Vec;
Changing
//Vec.test.js
const Vec = require('./Vec');
const myVec = new Vec(); //TypeError: Vec is not a constructor
to
//Vec.test.js
const {Vec} = require('./Vec');
const myVec = new Vec(); //Succeeds!
resolved this error for me.
In my case I was using the prototype name as the object name. For e.g.
function proto1()
{}
var proto1 = new proto1();
It was a silly mistake but might be of help to someone like me ;)
Sometimes it is just how you export and import it. For this error message it could be, that the default keyword is missing.
export default SampleClass {}
Where you instantiate it:
import SampleClass from 'path/to/class';
let sampleClass = new SampleClass();
Option 2, with curly braces:
export SampleClass {}
import { SampleClass } from 'path/to/class';
let sampleClass = new SampleClass();
I just want to add that if the constructor is called from a different file, then something as simple as forgetting to export the constructor with
module.exports = NAME_OF_CONSTRUCTOR
will also cause the "Not a constructor" exception.
To add to #wprl's answer, the ES6 object method shorthand, like the arrow functions, cannot be used as a constructor either. 😅
const o = {
a: () => {},
b() {},
c: function () {}
};
const { a, b, c } = o;
new a(); // throws "a is not a constructor"
new b(); // throws "b is not a constructor"
new c(); // works
Car.js
class Car {
getName() {return 'car'};
}
export default Car;
TestFile.js
const object = require('./Car.js');
const instance = new object();
error: TypeError: instance is not a constructor
printing content of object
object = {default: Car}
append default to the require function and it will work as contructor
const object = require('object-fit-images').default;
const instance = new object();
instance.getName();
In my case this happened due to a circular reference between two classes. I imported class B in the class A file and imported class A in the class B file, so the program never reached to the point of actually define A as a class.
I just had a similar error when trying to use the BS5ModalJS in conjunction with webpack, meaning I was trying to import the js file.
Because the single .js file provided was designed to be used via the script tags, it took a while for me to realise that to avoid the "BSModal is not a constructor" error, I had to go into their code and add:
export {BSModal}
I was then able to use
import { BSModal } from './../thirdparty/BS5ModalJS/BS5Modal.js';
and do
let myModal enter code here= new BSModal(...)
without getting that error.
So if you're using webpack, perhaps make sure the classes and functions are exported (and therefore available) to the callers.
In my case I'd forgotten the open and close parantheses at the end of the definition of the function wrapping all of my code in the exported module. I.e. I had:
(function () {
'use strict';
module.exports.MyClass = class{
...
);
Instead of:
(function () {
'use strict';
module.exports.MyClass = class{
...
)();
The compiler doesn't complain, but the require statement in the importing module doesn't set the variable it's being assigned to, so it's undefined at the point you try to construct it and it will give the TypeError: MyClass is not a constructor error.
I had a similar error and my problem was that the name and case of the variable name and constructor name were identical, which doesn't work since javascript interprets the intended constructor as the newly created variable.
In other words:
function project(name){
this.name = name;
}
//elsewhere...
//this is no good! name/case are identical so javascript barfs.
let project = new project('My Project');
Simply changing case or variable name fixes the problem, though:
//with a capital 'P'
function Project(name){
this.name = name;
}
//elsewhere...
//works! class name/case is dissimilar to variable name
let project = new Project('My Project');
It is happening because you must have used another variable named "project" in your code. Something like
var project = {}
For you to make the code work, change as follows:
var project = {} into var project1 = {}
To add the solution I found to this problem when I had it, I was including a class from another file and the file I tried to instantiate it in gave the "not a constructor" error. Ultimately the issue was a couple unused requires in the other file before the class was defined. I'm not sure why they broke it, but removing them fixed it. Always be sure to check if something might be hiding in between the steps you're thinking about.
In browse (assuming your app is running), inspect, source, and make sure the javascript file for the constructor is loaded.
For me this happened because of a small typo.
I had a class export like ->
module.export = class TestClass {
constructor() {}
}
And I was trying to use this class as ->
const testClass = new TestClass();
The problem and typo was at module.export, which should be module.exports so
module.exports = class TestClass { // module.exports here instead of export
constructor() {}
}

Categories

Resources