I'm trying to import an object into another JS file, and I keep getting this error, Uncaught ReferenceError: Cannot access 'stocks' before initialization. I've declared stocks, and I've imported it correctly, so I can't see what I did wrong. Any help is much appreciated. Thanks.
In the stocks file:
export const stocks = {
megaCorp: {
name: 'Mega Corporation',
value: decideStockValue(),
portIn: 0,
document: "mega"
},
lunaBake: {
name: "Luna Baking",
value: decideStockValue(),
portIn: 1,
document: "luna"
},
}
And in the user file :
import { stocks } from "./stocks.js";
export let user = {
money: 2000,
portfolio: [0, 0, 0, 0]
}
function getValue () {
let value = user.money;
let cannon = stocks.cannonRock.value * user.portfolio[0];
let alpha = stocks.alphaComp.value * user.portfolio[1];
let luna = stocks.lunaBake.value * user.portfolio[2];
let mega = stocks.megaCorp.value * user.portfolio[3];
value += cannon;
value += alpha;
value += luna;
value += mega;
return value;
}
user.value = getValue();
Again Looking at the code it seems syntactically fine, so this is not an answer but i rather want to share a snippet of code to see how it behaves.
The error you shared Uncaught ReferenceError: Cannot access 'variable_name' before initialization is thrown when a lexical variable was accessed before it was initialized ( what is known as a temporal dead zone error), however in the code you share there is nothing that should throw this error.
for example this code will throw this error
const x = 3
function a(){
console.log(x)
const x = 5;
}
a()
Assuming indeed that the error originated from the user file, then the following code might solve it. In the code u had getValue was a function expression that should be hoisted ( which again should be fine), but it could be that a bundler you are using is misbehaving.
import { stocks } from "./stocks.js";
const getValue = (stocks, money, portfolio) => {
let value = money;
let cannon = stocks.cannonRock.value * portfolio[0];
let alpha = stocks.alphaComp.value * portfolio[1];
let luna = stocks.lunaBake.value * portfolio[2];
let mega = stocks.megaCorp.value * portfolio[3];
value += cannon;
value += alpha;
value += luna;
value += mega;
return value;
};
const money = 2000;
const portfolio = [0, 0, 0, 0];
export const user = {
money,
portfolio,
value: getValue(stocks, money, portfolio),
};
After debugging for a little, I closed the server and opened it again. This time, it worked fine. I'm still not sure why the original error happened, but now it's working great. Thanks for everyone's help
This is a classic example of cycle overloading of certain dependancy (c) Sergei Vohmianin
The easiest thing you can do is to move that object into it's separate module just to omit cycle like app => method => app.
I was getting this error ReferenceError: Cannot access 'process' before initialization
when I attempted to do this:
require("dotenv-safe").config();
console.log(process.env);
const DATABASE_URI = process.env.DATABASE_URI;
Turns out, the problem was I was mistakenly declaring process further down in the same file like this:
const process = require("process");
This require was unnecessary since it's available in Node's global context. Deleting that line fixed the problem.
Related
I am trying to implement a deep learning model in the browser and this requires porting some custom layers, one of them is an instant layer normalization. Below the piece of code that is supposed to work but it's a bit old.
I get this error:
Uncaught (in promise) ReferenceError: initializer is not defined
at InstantLayerNormalization.build
<script src="https://cdn.jsdelivr.net/npm/#tensorflow/tfjs/dist/tf.min.js"> </script>
<script>
class InstantLayerNormalization extends tf.layers.Layer
{
static className = 'InstantLayerNormalization';
epsilon = 1e-7
gamma;
beta;
constructor(config)
{
super(config);
}
getConfig()
{
const config = super.getConfig();
return config;
}
build(input_shape)
{
let shape = tf.tensor(input_shape);
// initialize gamma
self.gamma = self.add_weight(shape=shape,
initializer='ones',
trainable=true,
name='gamma')
// initialize beta
self.beta = self.add_weight(shape=shape,
initializer='zeros',
trainable=true,
name='beta')
}
call(inputs){
mean = tf.math.reduce_mean(inputs, axis=[-1], keepdims=True)
variance = tf.math.reduce_mean(tf.math.square(inputs - mean), axis=[-1], keepdims=True)
std = tf.math.sqrt(variance + self.epsilon)
outputs = (inputs - mean) / std
outputs = outputs * self.gamma
outputs = outputs + self.beta
return outputs
}
static get className() {
console.log(className);
return className;
}
}
tf.serialization.registerClass(InstantLayerNormalization);
</script>
The methods of the inherited class tf.layers.Layer are not called properly.
self in python is this in js
add_weight is rather addWeight
Here is the signature of the addWeight method. Please notice that in js there is not the format variable=value for function arguments destructuring assignment
// instead of this
self.gamma = self.add_weight(shape=shape, initializer='ones', trainable=true, name='gamma')
// it should rather be
this.gamma = this.addWeight('gamma', shape, undefined, 'ones', undefined, true)
I am doing some research on a running website, and the behavior of the code just surprises me.
They defined a function named '__jsload' and bind it to window.
window._jsload = function(hJ, hK) {
var i = d2.getModuleInfo(hJ);
i.status = d2.Request.LOADED;
if (hK !== "") {
d2.run(hJ, hK)
} else {
if (window.map) {
var e = new a6("ongetmodules_fail");
e.moduleName = hJ;
window.map.fire(e)
}
var T = document.createElement("script");
var hI = d2.MD5Mapping[hJ];
T.src = d2.Config.jsModPath + hJ + "_" + hI + ".js";
document.getElementsByTagName("head")[0].appendChild(T)
}
};
In the run function, there's only an eval(), it seems nothing is stored for future use.
run: function(T, hI) {
var hM = this.getModuleInfo(T);
var hP = this.Dependency[T];
if (hP) {
for (var hK = 0; hK < hP.length; hK++) {
var hL = this.getModuleInfo(hP[hK]);
if (hL.status !== this.Request.COMPLETED) {
hL.modsNeedToRun.push({
name: T,
code: hI
});
return
}
}
}
try {
eval(hI)
} catch (hN) {
return
}
hM.status = this.Request.COMPLETED;
for (var hK = 0, hJ = hM.callbacks.length; hK < hJ; hK++) {
hM.callbacks[hK]()
}
hM.callbacks.length = 0;
for (hK = 0; hK < hM.modsNeedToRun.length; hK++) {
var hO = hM.modsNeedToRun[hK];
this.run(hO.name, hO.code)
}
hM.modsNeedToRun.length = 0
},
Then all the module are written in the following manner.
/**/_jsload&&_jsload(
// this should be the module name
'glcommon',
// this should be the module content
'function aO(e,i)......'
)
I have a little experience in coding in python, so I thought those loaded modules will be special objects, and I can access functions defined in the module by just calling them.
import pandas as pd
pd.DataFrame()
And I searched some references on coding in javascript, they mentioned something like 'import/export' and maybe 'require'. After importing the module, I can call exported function just by calling the name.
// in sayHi.js
export function sayHi(user) {
alert(`Hello, ${user}!`);
}
// in main.js
import {sayHi} from './sayHi.js';
alert(sayHi); // function...
sayHi('John'); // Hello, John!
None of these things happens in that website I'm researching on. There's even no 'export' in the whole module text.
So, here rises my question.
Is it possible to call the function in a module in the web console? If it's not bound to the window object, will it still be possible?
We all know that currently a lot of web pages are dynamic, when a certain event happens, a certain function relate to it should be called. So, where are those functions saved? Are they still reachable during the web is running?
3.How can I debug modules like the above ones, when you can't get a pretty printed version of code and make some breakpoints? I tried to go step by step, but all the functions go into the text versioned module, and I can't make a breakpoint.
I'm trying to assign function to multiple variables, the function calls another function getFuncName(), I want getFuncName to return the name of the function that got invoked.
function getFuncName() {
return getFuncName.caller.name;
}
const error = warning = info = verbose = debug = silly = message => {
console.log(getFuncName())
}
When error gets invoked it prints silly, same for warning, info, verbose and debug.
I want that if error gets invoked, it will print error, same for every other variable, Thanks.
The only way you do it is to:
const error = message => {
console.log(getFuncName())
}
const warning = error
const info = error
// etc
On the other hand why would you want to do this? Maybe you wanted to push a log level or something? In this case you could do like this (higher-order functions):
const logger = level => message => {
console.log(level, ': ', getFuncName())
}
const error = logger('error')
// etc
Don't use Function.caller, it's non-standard and does not behave consistently across browsers. It also does not work in strict mode:
'use strict';
function foo () {
function bar () {
console.log(bar.caller.name);
}
return bar();
}
foo();
Just use partial application to create a closure for message => { ... }:
'use strict';
const logger = type => message => {
console.log(type, message);
};
const error = logger('error');
const warning = logger('warning');
const info = logger('info');
const verbose = logger('verbose');
const debug = logger('debug');
const silly = logger('silly');
error('foo');
info('bar');
In your code, besides getFuncName, there is only a single function in existence. It's referred to via 6 different variables, but there is only one function, with one name.
You can't expect the same function to have different names at different times. Anonymous functions can be given a default name by the interpreter when they appear in the code assigned to a variable - in the case that the anonymous function is assigned to multiple variables at once, the rightmost variable name ("silly", in your case) is considered the name of the function.
A one-liner solution from #Patrick Roberts's answer:
const [error, warning, info, verbose, debug, silly] = ['error', 'warning', 'info', 'verbose', 'debug', 'silly'].map(type => msg => {console.log(type, msg);});
var history=[];
function log(p,i,pm,y,m)
{
var details = {
amt:p,
int:i,
paym:pm,
yea:y,
mon:m
};
history.push(details); //error is here. Uncaught TypeError: history.push is not a function
var currDetails = history[history.length-1];
document.getElementById("mydiv").innerHTML += currDetails.amt;
}
I am trying push the data into history array. But, why am i keep getting error?
Basically you are accessing the global window property history and it is read only. You are getting the error because there is no push() implemented on that property. Try some other name so that it does not match with any of the global window property to get the expected behavior from the declared variable:
var historyArr=[];
function log(p,i,pm,y,m)
{
var details = {
amt:p,
int:i,
paym:pm,
yea:y,
mon:m
};
historyArr.push(details);
var currDetails = historyArr[historyArr.length-1];
console.log(currDetails)
}
log('a','b','c','d','e');
The global variable history is predefined in browsers and is read only.
var history=[]; therefore fails silently.
history.push therefore fails because history is not an array object.
Wrap your code in an IIFE so that you aren't trying to create unneeded variables in the global scope, this will mean you can create a history variable as you won't be overwriting the existing one.
var log = (function() {
var history = [];
function log(p, i, pm, y, m) {
var details = {
amt: p,
int: i,
paym: pm,
yea: y,
mon: m
};
history.push(details); //error is here. Uncaught TypeError: history.push is not a function
var currDetails = history[history.length - 1];
document.getElementById("mydiv").innerHTML += currDetails.amt;
}
return log;
})();
(This is a simplified version of the revealing module pattern.
So if you open up the inspector, you get this (if you're unlucky):
I'm building a tiny JS component which displays debugging information - is there any way to read the number of encountered errors and warnings so far?
A hacky solution I could come up with involves a bit of trickery by replacing the console.(error|log|warn) functions with my own, but I'm yet to test if it works for all cases (e.g. outside of code I own).
Is there a better way to do this?
As noted in this answer, it's generally not a good idea to change the behavior of native objects/methods. However, the following code should get you what you need in a fairly innocuous manner:
// Add this IIFE to your codebase:
(() => {
// Get all of the property names of the console:
const methodsToTrack = Object.keys(window.console);
// Create an object to collect total usage tallies in:
const usageRegistry = {};
for (let i = 0, j = methodsToTrack.length; i < j; i++) {
let methodName = methodsToTrack[i];
// If the property is not a method, don't touch it:
if(typeof window.console[methodName] !== 'function') {
continue;
}
// Cache the original console method here:
let consoleMethod = window.console[methodName];
// Overwrite console's method to increment the counter:
window.console[methodName] = function () {
// Defining registry properties here, so the registry only contains values for methods that were accessed:
usageRegistry[methodName] = usageRegistry[methodName] || 0;
// Execute the original method's behavior, capturing the returned value (if any) in a var, to return it at the end:
const returnedValue = consoleMethod(...arguments);
// Increment the usage registry for the executed method:
usageRegistry[methodName]++;
// Return the value the console's method would have returned, so the new method has the same signature as the old.
return returnedValue;
};
}
// Define a funciton to output the totals to a console log, then clean up after itself:
window.showConsoleTallies = function () {
window.console.log(usageRegistry);
usageRegistry['log']--;
}
})();
// Examples:
showConsoleTallies();
console.log('log 1');
console.error('error 1');
console.log('log 2');
console.warn('warn 1');
console.error('error 2');
console.log('log 3');
showConsoleTallies();
PS: That's the ECMA6 version, but feel free to run it through Babel if you'd like it to be compiled for use in older browsers.