today I met a bug I have never seen before, also, there is none of relevant SO post about this.
ReferenceError: Cannot access 'Math' before initialization
I have tried to add IIFE but still not working.
In my previous work on web dev, I never needed to include math.js or import it, I always thought it was provided. Before my last attempt, it always works fine, in my other scripts, I can call Math.abs, Math.floor, etcetera.
Sorry I could not provide any minimum working example, here is the full error reporting.
Uncaught ReferenceError: Cannot access 'Math' before initialization
This is the script I am trying to run:
// round to 2 decimal places
const rit = val => Math.round(val * 100) / 100;
function render_element(styles, el) {
for (const [kk, vv] of Object.entries(styles)) {
el.style[kk] = vv;
}
}
class Clock{
// unit: min
static day(){
return 1440;
}
constructor(str){
var [h, min] = str.split(':');
this.h = parseInt(h);
this.min = parseInt(min);
}
concat(){
return new Clock(this.parse());
}
// convert clock h, min to min
minutes(){
return this.h * 60 + this.min
}
// pass in a clock, return gap in minute
gap(clock){
return Math.abs(this.minutes() - clock.minutes());
}
gaplength(clock, h, min, length){
return this.gap(clock) / (h * 60 + min) * length;
}
parse(){
var h = this.h.toString();
var min = this.min.toString();
min = min.length == 1 ? min + '0' : min;
return h + ':' + min;
}
add_h(h){
if(this.h + h >= 24){
this.h = this.h + h - 24;
}else{
this.h += h;
}
}
add_min(min){
if(this.min + min >= 60){
this.add_h(1);
this.min = this.min + min - 60;
}else{
this.min = this.min + min;
}
}
}
class Period{
// pass in two clock object
constructor(from_, to_){
this.from_ = from_.concat();
this.to_ = to_.concat();
}
concat(){
return new Period(this.from_, this.to_);
}
gap(){
return this.from_.gap(this.to_);
}
gaplength(h, min, length){
return this.from_.gaplength(this.to_, h, min, length);
}
shift_min(min){
this.from_.add_min(min);
this.to_.add_min(min);
}
shift_h(h){
this.from_.add_h(h);
this.to_.add_h(h);
}
}
class Subject{
constructor(
bg_url,
name,
course,
teacher,
start, // string, e.g. 12:45
finish,
color,
){
this.bg_url = 'img/' + bg_url;
this.name = name;
this.course = course;
this.teacher = teacher;
this.start = new Clock(start);
this.finish = new Clock(finish);
this.color = color;
this.duration = new Period(this.start, this.finish);
// percents
this.left = rit(this.start.gaplength(new Clock('11:00'), 7, 0, 100));
this.width = rit(this.duration.gaplength(7, 0, 100));
this.card_style = {
position: 'relative',
width: '20%',
height: '20%',
borderRadius: '20px',
};
this.card_content_style = {
position: 'absolute',
width: '20%',
height: '20%',
borderRadius: '20px',
};
this.h1_style = {
width: '100%',
height: '5%',
fontSize: '1.2em',
padding: '0 5px 5px 5px',
};
this.course_style = {
width: '100%',
height: '5%',
textAlign: 'center',
fontSize: '1.2em',
fontWeight: 'bold',
};
this.teacher_style = {
width: '100%',
height: '5%',
fontSize: '1.2em',
fontStyle: 'italic',
textAlign: 'right',
};
this.btn_wrapper_style = {
position: 'absolute',
top: '0',
right: '0',
width: '40%',
height: '35%',
borderRadius: '20px',
zIndex: '100',
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
};
this.btn_style = {
width: '45%',
height: '45%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
borderRadius: '10px',
fontWeight: 'bold',
cursor: 'pointer',
overflow: 'hidden',
};
this.modify_mouseenter_style = {
background: 'gold',
color: 'black',
};
this.modify_mouseleave_style = {
background: 'orange',
color: 'white',
};
this.remove_mouseenter_style = {
background: 'pink',
color: 'black',
};
this.remove_mouseleave_style = {
background: 'orchid',
color: 'white',
};
this.card_el = document.createElement('div');
render_element(this.card_style, this.card_el);
this.img_el = document.createElement('img');
this.img_el.setAttribute('src', this.bg_url);
this.img_el.style.opacity = 0.3;
this.card_content_el = document.createElement('div');
render_element(this.card_content_style, this.card_content_el)
this.h1_el = document.createElement('h1');
this.h1_el.innerHTML = this.name;
render_element(this.h1_style, this.h1_el);
this.hr_el = document.createElement('hr');
this.hr_el.style.borderColor = this.color;
this.hr_el.style.opacity = '0.5';
this.course_el = document.createElement('p');
this.course_el.innerHTML = this.course;
render_element(this.course_style, this.course_el);
this.teacher_el = document.createElement('p');
this.teacher_el.innerHTML = this.teacher;
render_element(this.teacher_style, this.teacher_el);
this.btn_wrapper_el = document.createElement('div');
render_element(this.btn_wrapper_style, this.btn_wrapper_el);
this.btn_modify_el = document.createElement('div');
this.btn_modify_el.innerHTML = 'modify';
render_element(this.btn_style, this.btn_modify_el);
this.btn_remove_el = document.createElement('div');
this.btn_remove_el.innerHTML = 'remove';
render_element(this.btn_style, this.btn_remove_el);
this.card_el.appendChild(this.img_el);
this.card_el.appendChild(this.card_content_el);
this.card_content_el.appendChild(this.h1_el);
this.card_content_el.appendChild(this.hr_el);
this.card_content_el.appendChild(this.course_el);
this.card_content_el.appendChild(this.teacher_el);
this.card_el.appendChild(this.btn_wrapper_el);
this.btn_wrapper_el.appendChild(this.btn_modify_el);
this.btn_wrapper_el.appendChild(this.btn_remove_el);
this.becomeChildOf = this.becomeChildOf.bind(this);
this.modifyMouseEnter = this.modifyMouseEnter.bind(this);
this.modifyMouseLeave = this.modifyMouseLeave.bind(this);
this.removeMouseEnter = this.removeMouseEnter.bind(this);
this.removeMouseLeave = this.removeMouseLeave.bind(this);
this.btn_modify_el.addEventListener('mouseenter', this.modifyMouseEnter);
this.btn_modify_el.addEventListener('mouseleave', this.modifyMouseLeave);
this.btn_remove_el.addEventListener('mouseenter', this.removeMouseEnter);
this.btn_remove_el.addEventListener('mouseleave', this.removeMouseLeave);
}
becomeChildOf(parent_el){
this.parent_el = parent_el;
this.parent_el.appendChild(this.card);
}
modifyMouseEnter(){
render_element(this.modify_mouseenter_style, this.btn_modify_el);
}
modifyMouseLeave(){
render_element(this.modify_mouseleave_style, this.btn_modify_el);
}
removeMouseEnter(){
render_element(this.remove_mouseenter_style, this.btn_remove_el);
}
removeMouseLeave(){
render_element(this.remove_mouseleave_style, this.btn_remove_el);
}
}
class VisualArts extends Subject{
constructor(
course,
teacher,
start,
finish,
){
super(
'visual-arts.jpg',
course,
teacher,
start,
finish,
'red',
)
}
}
new VisualArts(
'Visual Arts',
'James Collin',
'11:00',
'11:45',
)
error occurs at:
// pass in a clock, return gap in minute
gap(clock){
return Math.abs(this.minutes() - clock.minutes());
}
Update
To run an entire script, I can do:
console.log(Math.abs(-1));
But in the script above, I cannot do:
gap(clock){
var min = this.minutes() - clock.minutes();
console.log(Math.abs(-1));
// ReferenceError: Cannot access 'Math' before initialization
return Math.abs(min);
}
I have literally no idea why this happens
In addition, for testing the script, you don't need html or css.
I do appreciate your suggestion.
I think this might be the initiator of the issue :-
You're
superexpects 7 arguments sinceSubjectconstructor takes 7. When you're passing them 6, you will be messing the order of values assigned tostartandfinishwhich are responsible for constructing yourClockobjects. They are not getting11.00and11:45as you wanted.