【问题标题】:Variables declared inside the function scope causes if statement an error在函数范围内声明的变量会导致 if 语句出错
【发布时间】:2017-05-02 11:12:05
【问题描述】:

所以我在 if 语句 var messagevar body 的回调函数中声明了两个变量,现在当我运行代码时,当 if 语句命中 else 语句然后它抛出 Uncaught TypeError: Cannot read property 'parentNode' of undefined at HTMLButtonElement.<anonymous> 时出现错误 当我从声明中删除 var 关键字并全局声明它们时,我没有收到任何错误。问题是什么?我虽然 javascript 是函数范围语言,而不是块范围。即使在函数顶部的 if 语句之外声明它们也无济于事。

代码:

function clickBtn() {
  var btn = document.getElementById("button");
  btn.addEventListener("click", function () {
    if (theName.value == "") {
      var message = document.createElement("p");
      message.className = "message";
      message.innerHTML = "You forgot the name and email";
      var body = document.getElementsByTagName("body")[0];
      body.appendChild(message);
    } else {

    message.parentNode.removeChild(message);
    var user1 = new User (theName.value, theEmail.value);
    users.push(user1);
    console.log(JSON.stringify(users, null, 2));
  }
    theName.value = "";
    theEmail.value = "";
  });
}
clickBtn();

【问题讨论】:

  • 什么是theName?请也出示该代码!
  • 当你说问题没有发生时,你能显示代码吗?

标签: javascript scope closures var


【解决方案1】:

只有当if 的值为true 时,您才会为message 赋值。

else 分支只有一个未定义的值 message,这就是您收到此错误的原因。

您可以通过将message 变量声明为具有if/else 语句之外的值来解决此问题。


您似乎想添加 if 中的消息并删除 else 中的消息 - 为此,您需要能够获得相同的信息。您所做的是每次都创建新消息

以下是您可以执行的操作的示例(基于您的代码):

function clickBtn() {
  var btn = document.getElementById("button");
  btn.addEventListener("click", function () {
    if (theName.value == "") {
      var message = document.createElement("p");
      message.className = "message";
      message.innerHTML = "You forgot the name and email";
      var body = document.getElementsByTagName("body")[0];
      body.appendChild(message);
    } else {
      message = document.getElementsByClassName("message")[0]; // first one
      message.parentNode.removeChild(message);
      var user1 = new User (theName.value, theEmail.value);
      users.push(user1);
      console.log(JSON.stringify(users, null, 2));
  }
    theName.value = "";
    theEmail.value = "";
  });
}
clickBtn();

【讨论】:

  • btn.addEventListener("click", function () { var message = document.createElement("p"); message.className = "message"; message.innerHTML = "You forgot the name and email"; var body = document.getElementsByTagName("body")[0]; if (theName.value == "") { body.appendChild(message); } else { message.parentNode.removeChild(message);我改了,但现在我得到一个错误Uncaught TypeError: Cannot read property 'removeChild' of null at HTMLButtonElement.&lt;anonymous&gt;
  • @Limpuls - 您只在 if 子句中将 message 附加到 DOM - 如果您不将它附加到任何东西,您希望它有父节点?
  • 那该怎么办?只有当输入为空并且用户输入内容时,我才需要附加它,然后删除附件。我看不出我怎么能一直附加它而不在 if 语句案例中显示实际的 innerHTML 消息,或者我可以吗?
  • @Limpuls - 如果它具有 parentNode: if(message.parentNode) { message.parentNode.removeChild(message) },则只有分离/删除。事实上,如果它不存在,你就没有添加它。
  • 我这样做了var btn = document.getElementById("button"); btn.addEventListener("click", function () { var message = document.createElement("p"); message.className = "message"; var body = document.getElementsByTagName("body")[0]; body.appendChild(message); if (theName.value == "") { message.innerHTML = "You forgot the name and email"; } else { message.parentNode.removeChild(message); 我的意思是当您在 if 或 else statmenet 之后刷新页面时它正在工作,但在同一个会话中它不起作用。即使在用户输入后消息仍保留在此处
【解决方案2】:

如果 if 语句为真,则声明变量,如果为假,则引用它。在 if 语句之前声明 var message=... ,它应该可以工作。

【讨论】:

    【解决方案3】:

    虽然 javascript 是函数作用域语言,而不是块作用域

    现代代码看起来有点不同,它以函数式风格和不变性为目标。从版本 6 开始的 ES-262 也更高,最好只使用 const 和 let,并且为了将来与 ES 模块的兼容性,直接包含使用严格模式。 在将此类更正输入代码后,阶段运行时的错误很可能会传递到阶段的编译时。此外,如果需要,最好解决功能关闭问题,而不是使用全局信息字段。

    【讨论】:

      【解决方案4】:

      Javascript 有一个变量hoisting 的概念。 Javascript 确实是函数范围的语言,而不是块范围的语言。 在您的情况下,var messagevar body 都被提升到函数的顶部而没有被分配任何值(因此具有未定义的值)。

      它只在 if 块中被赋值,在 else 块中是未定义的。

      “No var”将查找作用域链,直到找到变量或到达全局作用域(此时它将创建它)。当您从声明中删除 var 关键字时,var messagevar body 将在全局范围内声明,并且还分配了赋值中提供的值。因此它不会抛出错误。

      在全局范围内声明这些变量而不为它们分配任何值会导致 var messagevar body 在显式分配值之前未定义。因此 else 部分会引发错误。

      【讨论】:

        【解决方案5】:

        是的,关于变量是函数范围而不是块范围是正确的。但是,只有在到达赋值指令时,Javascript 才会为您的变量赋值。在您的情况下,您将赋值指令(message = document.createElement("p");)放在 if 中,这意味着当条件不满足时不会执行该指令。并且 Javascript 被提升,这意味着 它将变量的所有声明(并且仅声明) 移动到函数的顶部。所以message的声明被移动到函数的顶部并保持undefined,当你尝试访问.parentNode你会得到错误,因为undefined没有属性。查看更多详情:https://scotch.io/tutorials/understanding-hoisting-in-javascript

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-07-31
          • 1970-01-01
          • 2020-06-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多