JS错误:无法读取属性'长度'

时间:2018-01-15 23:15:40

标签: javascript arrays random

我想从数组中获取一个随机数,但我收到错误:无法读取属性' length'。

  //Attack arr
  var attackID = [0,1];

  //Start game
  function start(){
    console.log("Your new username is "+localuser.username+"!");
    var r_atk = Math.round(Math.random()*(attackID.length-1));

    if(attacks[r_atk] == 0){
      punch(enemy.name);
    }
    else if(attacks[r_atk] == 1){
      kick(enemy.name);
    }
  }

要查看完整代码,请点击Here然后按ctrl + u

4 个答案:

答案 0 :(得分:0)

在定义start数组之前,您正在调用attackID函数。只需在attackID内移动start()声明,因为您无论如何都无法在其他任何地方使用它。

function start(){
  var attackID = [0,1];
  console.log("Your new username is "+localuser.username+"!");
  var r_atk = Math.round(Math.random()*(attackID.length-1));
  // ...
}

答案 1 :(得分:0)

<强>修

游戏的代码实际上包含两个错误。第二个错误不会立即显现,因为它被第一个错误消息遮盖了。问题是攻击既不是变量也不是属性,因为它从未在代码中声明或定义,因此在解决第一个错误后会出现ReferenceError。

Google Chrome开发者工具中显示的第一条错误消息指出:

  

未捕获的TypeError:无法读取属性&#39;长度&#39;未定义的

控制台指出有问题的代码是:

var r_atk = Math.round(Math.random()*(attackID.length-1));

然而,代码行本身在语法上是正确的, attackID 在函数声明之前,带有声明并定义变量的单行。您可能认为解决方案是捕获TypeError。我试过here无济于事。真正的问题涉及一个名为 hoisting 的概念,其中JavaScript变量和函数声明被移动到&#34; ...最近的范围&#34; (见here)。当 attackID 被提升时,它将评估为未定义。因此,当start()执行时,它无可救药地尝试访问未定义变量的长度属性,最终结果产生TypeError。

实用的解决方案涉及删除专门调用start()的行。由于start()的函数声明位于脚本的末尾,因此您可以将其转换为立即调用的函数表达式IIFE)。要创建IFFE,请在start()的函数声明周围加上括号,然后使用另一对,启用该函数以自动执行以及避免提升问题。每MDN

  

与函数不同,JavaScript中的函数表达式不会被挂起   声明。在定义之前,您不能使用函数表达式   他们......

现在,如果运行代码,与 attackID.length 关联的TypeError将消失,因为数组将在start()执行之前设置。

如果您运行以下代码,您将注意到 attackID.length 缺少TypeError,这允许与攻击关联的ReferenceError消息出现。

&#13;
&#13;
//Give user warning
console.warn("WARNING! This game is not close to being done yet\n\n\n\n");

function user(uname, HP, mana) {
  this.username = uname;
  this.HP = HP;
  this.mana = mana;
}

function enemy(ename, HP, mana) {
  this.name = ename;
  this.HP = HP;
  this.mana = mana;
}

var dmg = [0, 0, 0, 0, 5, 5, 5, 5, 10, 10, 10, 20, 30];
var enemy_dmg = [0, 0, 0, 0, 0, 5, 5, 5, 5, 10, 10, 10, 20, 30];

//Create user
var localuser = new user(null, 100, 100);
var enemy = new enemy("enemy1", 100, 100);

//Set user name
var newName = prompt("What do you want your username to be?");
localuser.username = newName;

//Attacks
function punch(target) { // atk 0
  if (target == localuser.username) {
    var r = Math.round(Math.random() * (dmg.length - 1));
    localuser.HP -= dmg[r];
    console.log(enemy.name + " punched you! Your HP is now " + localuser.HP + "!");
  } else if (target == enemy.name) {
    var r = Math.round(Math.random() * (dmg.length - 1));
    enemy.HP -= dmg[r];
    console.log("You punched " + target + "! His HP is now " + enemy.HP + "!");
  } else {
    console.warn("Make sure you put quotes around the enemy's name.");
  }
}

function kick(target) { // atk 1
  if (target == localuser.username) {
    var r = Math.round(Math.random() * (dmg.length - 1));
    localuser.HP -= dmg[r];
    console.log(enemy.name + " kicked you! Your HP is now " + localuser.HP + "!");
  } else if (target == enemy.name) {
    var r = Math.round(Math.random() * (dmg.length - 1));
    enemy.HP -= dmg[r];
    console.log("You punched " + target + "! His HP is now " + enemy.HP + "!");
  } else {
    console.warn("Make sure you put quotes around the enemy's name.");
  }
}

//Attack arr
let attackID = [0, 1];

//Start game
(function start() {
  console.log("Your new username is " + localuser.username + "!");
    var r_atk = Math.round(Math.random() * (attackID.length - 1));
    if (attacks[r_atk] == 0) {
      punch(enemy.name);
    } else if (attacks[r_atk] == 1) {
      kick(enemy.name);
    }
})();
&#13;
&#13;
&#13;

相关文章:

  • David Walsh Blog
  • Understanding Undefined and Preventing Referenceerrors
  • Older article on JS Best Practices
  • 答案 2 :(得分:0)

    在您声明start() start()之前attackID访问attackID之前,正在进行此操作。在使用start()函数之前,您应该fopen变量。或者使用内部功能范围。

    答案 3 :(得分:-1)

    在您的代码中,您在第38行调用函数start(),但您只在第74行声明并分配attackID数组。

    您必须在attackID函数中指定start(),或者您可以在文件的开头声明并指定所有变量。在代码之上分配将要重用的所有变量是一个很好的代码标准。