ReferenceError: Cannot access 'Math' before initialization

ReferenceError: Cannot access 'Math' before initialization

今天我遇到了一个我以前从未见过的错误,还有none的相关SOpost。

ReferenceError: Cannot access 'Math' before initialization

我已经尝试添加 IIFE,但仍然无法正常工作。 在我之前的 web dev 工作中,我从来不需要包含 math.js 或导入它,我一直认为它已经提供了。在我最后一次尝试之前,它总是工作正常,在我的其他脚本中,我可以调用 Math.abs, Math.floor,等等。

抱歉,我无法提供任何最低限度的工作示例,这里是完整的错误报告。

Uncaught ReferenceError: Cannot access 'Math' before initialization


这是我正在尝试 运行 的脚本:
// 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',
)

错误发生在:

    // pass in a clock, return gap in minute
    gap(clock){
        return Math.abs(this.minutes() - clock.minutes());
    }

更新

要运行一个完整的脚本,我可以做到:

console.log(Math.abs(-1));

但是在上面的脚本中,我做不到:

    gap(clock){
        var min = this.minutes() - clock.minutes();
        console.log(Math.abs(-1));
        // ReferenceError: Cannot access 'Math' before initialization
        return Math.abs(min);
    }

我完全不知道为什么会这样

此外,为了测试脚本,您不需要 html 或 css。

非常感谢您的建议。

我认为这可能是问题的始作俑者:-

class VisualArts extends Subject{
    constructor(
        course,
        teacher, 
        start,
        finish,
    ){
        super(
            'visual-arts.jpg',
            course, 
            teacher,
            start, 
            finish,
            'red',
        )
    }
}

super 期望 7 个参数,因为 Subject 构造函数需要 7 个参数。当你传递它们 6 个时,你会弄乱顺序分配给 startfinish 的值,它们负责构建您的 Clock 对象。他们没有得到您想要的 11.0011:45