title: ReferenceError: Cannot access 'Math' before initialization
body: <p>today I met a bug I have never seen before, also, there is none of relevant SO post about this.</p>
  <blockquote>
  <p>ReferenceError: Cannot access 'Math' before initialization</p>
  </blockquote>
  <p>I have tried to add IIFE but still not working.
  In my previous work on web dev, I never needed to include <code>math.js</code> or import it, I always thought it was provided. Before my last attempt, it always works fine, in my other scripts, I can call <code>Math.abs, Math.floor</code>, etcetera.</p>
  <p>Sorry I could not provide any minimum working example, here is the full error reporting.</p>
  <blockquote>
  <p>Uncaught ReferenceError: Cannot access 'Math' before initialization</p>
  </blockquote>
  <hr />
  This is the script I am trying to run:
  <pre class="lang-js prettyprint-override"><code>// round to 2 decimal places
  const rit = val =&gt; 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 &gt;= 24){
              this.h = this.h + h - 24;
          }else{
              this.h += h;
          }
      }
  
      add_min(min){
          if(this.min + min &gt;= 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',
  )
  </code></pre>
  <p>error occurs at:</p>
  <pre class="lang-js prettyprint-override"><code>    // pass in a clock, return gap in minute
      gap(clock){
          return Math.abs(this.minutes() - clock.minutes());
      }
  </code></pre>
  <hr >
  <h2>Update</h2>
  <p>To run an entire script, I can do:</p>
  <pre class="lang-js prettyprint-override"><code>console.log(Math.abs(-1));
  </code></pre>
  <p>But in the script above, I cannot do:</p>
  <pre class="lang-js prettyprint-override"><code>    gap(clock){
          var min = this.minutes() - clock.minutes();
          console.log(Math.abs(-1));
          // ReferenceError: Cannot access 'Math' before initialization
          return Math.abs(min);
      }
  </code></pre>
  <p>I have literally no idea why this happens</p>
  <p>In addition, for testing the script, you don't need html or css.</p>
  <p>I do appreciate your suggestion.</p>