`var` 未定义但不明白为什么

`var` comes as undefined but can't understand why

我一直在试图理解为什么我的位于 HTML 中的 js 代码在外部文件中无法正常工作。英语不是我的第一语言,这让我更难理解(而且西班牙语的结果并没有像我希望的那样富有成效)。

我从字面上将代码复制粘贴到另一个文件并放置 <script src="core.js"></script> 以加载 js,但 Firefox 和 Chrome 一直告诉我 "TypeError: eng is undefined" 何时加载。

在别人告诉我之前,已经在其他问题中回复了,是的,我看到了。但我什么都不懂,所以如果有人能像 "JS for dummies" 这样解释我,我将不胜感激。

密码是:

//SETS "LOCALE" "EN" TO REDIRECT TO ENGLISH
(function (){
  'use strict';

 var eng = document.querySelector('.eng')

  function setLocalStorage(){
     eng.addEventListener('click', () => {
      localStorage.setItem('locale','en')
    })
  }
  setLocalStorage()

}());

//SETS "LOCALE" "ES" TO REDIRECT TO SPANISH
(function (){
  'use strict';

  var esp = document.querySelector('.esp')

  function setLocalStorage(){
     esp.addEventListener('click', () => {
      localStorage.setItem('locale','es')
    })
  }
  setLocalStorage()

}());

//GETS THE "LOCALE" AND REDIRECT
(function () {
  'use strict';

  const locale = localStorage.getItem('locale');

  if (locale === 'en') {
    window.location = 'eng.html';

  } else if (locale === 'es') {
    window.location = 'esp.html';

  } else {
    // first visit:
    document
      .querySelector('.eng')
      .addEventListener('click', () => {
        localStorage.setItem('locale', 'en')
      });

    document
      .querySelector('.esp')
      .addEventListener('click', () => {
        localStorage.setItem('locale', 'es')
      });    
  }

}());

这一行JavaScript:

var eng = document.querySelector('.eng')

正在尝试访问 HTML 页面上的元素,该页面可能如下所示:

<div class="eng">english text here</div>

为了让 JavaScript 代码找到 HTML 元素,页面必须在 JavaScript 代码行运行之前已经加载。否则,document.querySelector('.eng') 表达式将 return 为空。

为了提高 HTML 在 JavaScript 运行之前加载和可用的机会,最好将脚本放在 <body> 元素的底部.像这样:

<body>
  <div class="eng">english text</div>
  <script src="myjavascript.js"></script>
<body>

但这并不能完全保证。为了进一步提高您的机会,您可以将 defer 属性添加到脚本标记,这会阻止脚本 运行 直到页面加载完成。

<script src="myjavascript.js" defer></script>

问题 #2 - 提升

JavaScript 代码还有一个问题可能会导致错误。这与 "hoisting" 有关,其中变量和函数声明在其块的顶部 "hoisted"。

这 JavaScript 涉及一些提升:

function () {
  'use strict';

  var eng = document.querySelector('.eng');

  function setLocalStorage () {
    eng.addEventListener('click', () => {
      localStorage.setItem('locale', 'en');
    });
  }

  setLocalStorage();

}

因为吊装,其实是这样做的:

function () {

  // declare 'eng' as undefined
  var eng; 

  // declare setLocalStorage
  function setLocalStorage () {

    // JavaScript interpreter says during declaration:
    // "TypeError: I don't know what 'eng.addEventListener' is"

    eng.addEventListener('click', () => {
      localStorage.setItem('locale', 'en');
    });
  }

  // set 'eng'
  eng = document.querySelector('.eng');

  // now that 'eng' is set, call setLocalStorage
  setLocalStorage();

}

修复 - 不要在提升函数中使用未设置的变量。这段代码做了同样的事情,没有任何吊装问题:

(function () {
  var eng = document.querySelector('.eng');

  eng.addEventListener('click', () => {
      localStorage.setItem('locale', 'en');
    });
})();

实际上,根据您的代码,您正在访问 DOM 元素,并且进一步调用它们来执行某些任务。但是假设您正在尝试访问一些不可用的 DOM 内容,然后告诉他们做某事。在这种情况下,如果您尝试访问某些 DOM 但 javascript 找不到它,它将 return undefined。这就是为什么你会得到 undefined。 (我试图简单地解释一下)

请确保您有一些具有 class 名称 engesp 的元素。

因此,要克服这种情况,您需要检查是否可以访问它们,然后分配一些任务。

假设我在这里检查 eng 是否存在,然后向其分配一些任务。

eng && eng.addEventListener('click', () => {
    localStorage.setItem('locale','en')
})

完整代码在这里。

//SETS "LOCALE" "EN" TO REDIRECT TO ENGLISH
(

    function (){
      'use strict';

     var eng = document.querySelector('.eng')

      function setLocalStorage(){
         eng && eng.addEventListener('click', () => {
          localStorage.setItem('locale','en')
        })
      }
      setLocalStorage()

    }());

    //SETS "LOCALE" "ES" TO REDIRECT TO SPANISH
    (function (){
      'use strict';

      var esp = document.querySelector('.esp')

      function setLocalStorage(){
         esp && esp.addEventListener('click', () => {
          localStorage.setItem('locale','es')
        })
      }
      setLocalStorage()

    }());

    //GETS THE "LOCALE" AND REDIRECT
    (function () {
      'use strict';

      const locale = localStorage.getItem('locale');

      if (locale === 'en') {
        window.location = 'eng.html';

      } else if (locale === 'es') {
        window.location = 'esp.html';

      } else {
        // first visit:
        document
          .querySelector('.eng')
          .addEventListener('click', () => {
            localStorage.setItem('locale', 'en')
          });

        document
          .querySelector('.esp')
          .addEventListener('click', () => {
            localStorage.setItem('locale', 'es')
          });    
      }

    }());