Why when I reassign a value to a variable inside a function, the variable becomes undefined and I get a type error?


baby carriage

My program is similar to a battleship, you can choose random blocks to shoot down two ships and they appear as hits or misses. I want it where I destroy a ship it will show a picture of the ship in the cemetery. It initially worked when I hardcoded where the boat was, but once I randomised the values ​​and had to reassign the new values ​​to my globals, the javascript to css broke. I get a type error telling me my global variable is undefined.

I have a section in my code called Part 1 that contains my global variables.

//PART 1
//var skiff = {name: "Skiff", length:2, spaces:[{hitbox:11, hitBefore:false},{hitbox: 12, hitBefore: false}], elem:"Skiff"};
var skiff = {name: "Skiff", length:2, spaces:[{hitbox:tinyBox1, hitBefore:false},{hitbox: tinyBox2, hitBefore: false}], elem:"Skiff"};

//var battleship ={name:"Battleship", length:3, spaces:[{hitbox:14, hitBefore:false},{hitbox: 15, hitBefore: false},{hitbox: 16, hitBefore: false}], elem:"Battleship"};
var battleship ={name:"Battleship", length:3, spaces:[{hitbox:largeBox1, hitBefore:false},{hitbox: largeBox2, hitBefore: false},{hitbox: largeBox3, hitBefore: false}], elem:"Battleship"};

var fleet = [skiff, battleship];

and part 2

//PART 2
fleet = [skiff, battleship];

If you set this line in your code, it will reassign the global variable to a random value instead of the ship's default. Part 2 is also in a function call MakeNewBoats, which creates random values ​​for variables, boats and ships, and their hitboxes. However, in return, the function called showGraveyard that displays the image of the boat when the boat is destroyed no longer works.

function showGraveyard(boats){

    for(var j=0; j<boats.length; j++){
        var boatDead = true;
    
        for(var x=0; x<boats[j].spaces.length; x++){
                if(boats[j].spaces[x].hitBefore==false){
                    boatDead = false;
                    break;
                }
        }
        if(boatDead==true){
            boats[j].elem.style.display="block";
        }
    }

}

The ship parameter is trying to get the fleet array variable to adjust the css for the appropriate ship, but is sending undefined. But if you comment out part 2,

//PART 2
//fleet = [skiff, battleship];

Once the ship is destroyed, the program successfully displays the ship. But the value of the boat is not random, but again takes the hardcoded default value from here.

//PART 1
//var skiff = {name: "Skiff", length:2, spaces:[{hitbox:11, hitBefore:false},{hitbox: 12, hitBefore: false}], elem:"Skiff"};
var skiff = {name: "Skiff", length:2, spaces:[{hitbox:tinyBox1, hitBefore:false},{hitbox: tinyBox2, hitBefore: false}], elem:"Skiff"};

//var battleship ={name:"Battleship", length:3, spaces:[{hitbox:14, hitBefore:false},{hitbox: 15, hitBefore: false},{hitbox: 16, hitBefore: false}], elem:"Battleship"};
var battleship ={name:"Battleship", length:3, spaces:[{hitbox:largeBox1, hitBefore:false},{hitbox: largeBox2, hitBefore: false},{hitbox: largeBox3, hitBefore: false}], elem:"Battleship"};

I don't understand why I am getting a type error.

Uncaught TypeError: boats[j].elem.style is undefined

This is my entire plan for the battleship.

<!DOCTYPE html>
<html>
<head>

    <title>Battleships</title>

    <meta charset="UTF-8">

    <style type="text/css">
        
        #title{
            font-text:25px;
            font-weight:bold;
        }
        
        #victoryText{
            font-size: 15px;
            background-color: yellow;
            width:45%
            float:left; 
        }
        
        #gameTable{
            border-collapse:collapse;
            border:1px solid gray;
            width:45%;
            float:left;
        }
        #displayId{
            font-size: 15px;
            background-color: yellow;
            width:45%
            float:left; 
        }
        
        .titleRow{
            background-color: rgb(201, 201, 201);
            border:1px solid rgb(201, 201, 201);
        }
        .landRow{
            background-color: rgb(255, 234, 204);
            border:1px solid rgb(255, 234, 204);
        }
        .waterRow{
            background-color: rgb(150,150,255);
            border:1px solid rgb(4,130,255);
        }
        .appt {
            background-color:rgb(255,80,80);
        }
        
        #button{
            margin-top: 15px;
            clear:left;
            float:left;
            background-color:pink;
        }
    
        
            
        #graveyard {
            float: right;
            width: 30%;
            height: 40%;
            margin-left: 30px;
            border: 1px double rgb(85, 0, 255);
            background-color: rgb(163, 117, 255);
         }

    
        .deadShips{
            display:none;
            clear:right;
            float: right;
            margin-right:30px;
            width: auto%;
            height: auto%;
            border: 1px solid #22FF6C;
            background-color:#8DFFB3;
        }
          
        td, th{
        border:1px solid black;
        padding:5px;
        height:10px;
        }
        
    </style>
        
    <script>

//----------------------------------------------------------------------
//----------------------------------------------------------------------
//LIBRARY OF FUNCTIONS
//showGraveyard
function showGraveyard(boats){

    for(var j=0; j<boats.length; j++){
        var boatDead = true;
    
        for(var x=0; x<boats[j].spaces.length; x++){
                if(boats[j].spaces[x].hitBefore==false){
                    boatDead = false;
                    break;
                }
        }
        if(boatDead==true){
            boats[j].elem.style.display="block";
        }
    }

}

function checkShot(fireShot,boats){
    
    for(var j=0; j<boats.length; j++){
        for(var i=0; i<boats[j].spaces.length; i++){
                if(fireShot==boats[j].spaces[i].hitbox){
                    if(boats[j].spaces[i].hitBefore){
                        return true;
                    }else{
                        boats[j].spaces[i].hitBefore=true;
                        showGraveyard(boats);
                        return true;
                    }
                }
        }
    }
    
    return false;
}

function checkForWinner(boats){

    for(var j=0; j<boats.length; j++){
        for(var x=0; x<boats[j].spaces.length; x++){
                if(boats[j].spaces[x].hitBefore==false){
                    return false;
                }
        }
    }
    return true;
}

function makeNewBoats(){
    var tinyStart = parseInt(Math.random()*(20-11)+11)-1;
    
    var tinyBox = [tinyStart, tinyStart+1];
    
    console.log("tinyBox: "+tinyBox);
    
    var largeStart = Math.floor(Math.random()*(20-12)+12)-2;
    
    var largeBox = [largeStart, largeStart+1, largeStart+2];
    
    console.log("largeBox: "+largeBox);
    
    for(var j=0; j<tinyBox.length; j++){
        for(var x=0; x<largeBox.length; x++){
            
            while(tinyBox[j]==largeBox[x]){
            
                    j=0;
                    
                    x=0;
                    
                    largeStart = Math.floor(Math.random()*(20-12)+12)-2;
    
                    largeBox = [largeStart, largeStart+1, largeStart+2];
                        
                    console.log("new largeBox: "+largeBox);
                
            }
        }
    }
    
    console.log("final tinyBox: "+tinyBox);
    
    console.log("final largeBox: "+largeBox);
    
    return[tinyBox,largeBox];
}


//----------------------------------------------------------------------
//----------------------------------------------------------------------
//GLOBAL VARIABLES

//create boats, boats will have values assigned to spaces, all of these boats will be put in a fleet, id for button clicked on check to see if one of the ids is one of the spaces, match remove from list of spaces, so the boat has fewer active elements, and update screen accordingly, and once removed every single space removed, you can start working on making the boat look sunk and in graveyard (hardcode ships)


var tinyBox1 = 11;
var tinyBox2 = 12;
    
var largeBox1 = 14;
var largeBox2 = 15;
var largeBox3 = 16;

var turnCounter = 0;

//PART 1
//var skiff = {name: "Skiff", length:2, spaces:[{hitbox:11, hitBefore:false},{hitbox: 12, hitBefore: false}], elem:"Skiff"};
var skiff = {name: "Skiff", length:2, spaces:[{hitbox:tinyBox1, hitBefore:false},{hitbox: tinyBox2, hitBefore: false}], elem:"Skiff"};

//var battleship ={name:"Battleship", length:3, spaces:[{hitbox:14, hitBefore:false},{hitbox: 15, hitBefore: false},{hitbox: 16, hitBefore: false}], elem:"Battleship"};
var battleship ={name:"Battleship", length:3, spaces:[{hitbox:largeBox1, hitBefore:false},{hitbox: largeBox2, hitBefore: false},{hitbox: largeBox3, hitBefore: false}], elem:"Battleship"};

var fleet = [skiff, battleship];

//--------------------------------------------------------------------
//----------------------------------------------------------------------

    
//MAIN PROGRAM
/** setRowHandlers take the class names of the odd and even rows in a table and gives each class mouseover and mouseout handlers that toggle the background color. */


function makeNewBoats(){
    var tinyStart = parseInt(Math.random()*(20-11)+11)-1;
    
    var tinyBox = [tinyStart, tinyStart+1];
    
    console.log("tinyBox: "+tinyBox);
    
    var largeStart = Math.floor(Math.random()*(20-12)+12)-2;
    
    var largeBox = [largeStart, largeStart+1, largeStart+2];
    
    console.log("largeBox: "+largeBox);
    
    for(var j=0; j<tinyBox.length; j++){
        for(var x=0; x<largeBox.length; x++){
            
            while(tinyBox[j]==largeBox[x]){
            
                    j=0;
                    
                    x=0;
                    
                    largeStart = Math.floor(Math.random()*(20-12)+12)-2;
    
                    largeBox = [largeStart, largeStart+1, largeStart+2];
                        
                    console.log("new largeBox: "+largeBox);
                
            }
        }
    }
    
    console.log("final tinyBox: "+tinyBox);
    
    console.log("final largeBox: "+largeBox);
    
    tinyBox1 = tinyBox[0];
    tinyBox2 = tinyBox[1];
    
    largeBox1 = largeBox[0];
    largeBox2 = largeBox[1];
    largeBox3 = largeBox[2];
    
    skiff = {name: "Skiff", length:2, spaces:[{hitbox:tinyBox1, hitBefore:false},{hitbox: tinyBox2, hitBefore: false}], elem:"Skiff"};

    //var battleship ={name:"Battleship", length:3, spaces:[{hitbox:14, hitBefore:false},{hitbox: 15, hitBefore: false},{hitbox: 16, hitBefore: false}], elem:"Battleship"};
    battleship ={name:"Battleship", length:3, spaces:[{hitbox:largeBox1, hitBefore:false},{hitbox: largeBox2, hitBefore: false},{hitbox: largeBox3, hitBefore: false}], elem:"Battleship"};
    //PART 2
    fleet = [skiff, battleship];
}



window.onload = function(){
    
    fleet[0].elem=document.getElementById(fleet[0].name);
    fleet[1].elem=document.getElementById(fleet[1].name);
    
    setRowHandlers("square");
    
    makeNewBoats();

}



function validate(buttonId, boats, displayId, victoryText){

    var fireShot = parseInt(buttonId.substring(1));
    
    turnCounter++;
    console.log(turnCounter);
    
    var boatHit = checkShot(fireShot, boats);
    console.log(boatHit+"boathit");
    if(boatHit){
        document.getElementById(buttonId).innerHTML="hit";
    }else{
        document.getElementById(buttonId).innerHTML="miss";
    }
        
    if (boatHit){
        var message ="It's a HIT!! You have used "+turnCounter+" shots.";
        document.getElementById(displayId).innerHTML=message;
        console.log(checkForWinner(boats)+"winner");
        var fleetSunk = checkForWinner(boats);
        
        if(fleetSunk){
            document.getElementById(victoryText).innerHTML = "</br>CONGRATS! All boats have been sunk.";
        }
    }else{
        var message ="It's a miss. You have used "+turnCounter+" shots.";
        document.getElementById(displayId).innerHTML=message;
    }
    
}

function mouseOverRiver(elem){
        if(elem.innerHTML=="hit"){
            elem.style.backgroundColor="red";
        }else if(elem.innerHTML=="miss"){
            elem.style.backgroundColor="green"; 
        }else{
            elem.style.backgroundColor="blue";
        }
}

function mouseOutRiver(elem){
//toggle between colors
    if(elem.innerHTML=="hit"){
            elem.style.backgroundColor="rgb(255,107,107)";
        }else if(elem.innerHTML=="miss"){
            elem.style.backgroundColor="rgb(150,255,124)";  
        }else{
            elem.style.backgroundColor="rgb(150,150,255)";
        }
}


function setRowHandlers(rowClassName){
//listener loop, get listeners on all squares
    var rows = document.getElementsByClassName(rowClassName);//produces array elements
    for(var i=0; i<rows.length; i++){
        rows[i].addEventListener( "mouseover", function(){mouseOverRiver(this)});
        rows[i].addEventListener( "click", function(){validate(this.id, fleet, "displayId", "victoryText");
        });
        
        rows[i].addEventListener( "mouseout", function(){mouseOutRiver(this)}); 
    }
}

//Reset, change position of the baots, resets bullets, change river squares back to normal, remove boats from graveyard, set "score back to 0"

function reset(fleet, square){

//change riversquares back to normal
for(var i=10;i<=19;i++){
    var id = "b"+i
    document.getElementById(id).innerHTML="";
    document.getElementById(id).style.backgroundColor="rgb(150,150,255)";
}

//reset bullet count
turnCounter = 0;
console.log(turnCounter);

document.getElementById("displayId").innerHTML="Click on the squares and sink the boats with the least amount of shots.";
document.getElementById("victoryText").innerHTML="";

//change position boats
makeNewBoats();

skiff = {name: "Skiff", length:2, spaces:[{hitbox:tinyBox1, hitBefore:false},{hitbox: tinyBox2, hitBefore: false}], elem:"Skiff"};
    
battleship ={name:"Battleship", length:3, spaces:[{hitbox:largeBox1, hitBefore:false},{hitbox: largeBox2, hitBefore: false},{hitbox: largeBox3, hitBefore: false}], elem:"Battleship"};

fleet = [skiff, battleship];

//remove boats graveyard


/*
for(var j=0; j<boats.length; j++){
        for(var x=0; x<boats[j].spaces.length; x++){
                    boats[j].elem.style.display="none";
        }
}

*/
}



//color changes when mouseover
//click on river, change color hit 
//when boat sink, it appears in graveyardcontinue clicking river
//when sink boat, yellow turns into you win
//clicking same river spot doesnt cost extra spots
//shots updates for each shot. its hit or miss. It's  hitt!! you have used x shots.
//makes new game, its new game and randomizes positions of boat
//Reset, change position of the baots, resets bullets, change river squares back to normal, remove boats from graveyard, set "score back to 0"
/*reset change position boats
--clear out .spaces (memory cup in boat)


*first boat
--generate random number from 0 to (9 - (.length-1) ) allow boat to fit
-- fill in .spaces


*second boat
--generate random number from 0 to (9 - (.length-1) ) allow boat to fit
-- fill in .spaces
--check for a overlap
    --if (no overlap) start game
    --else choose new positions
    --else redo second boat


//memory cup that says battleships have length 3 skips length 2


*/
    </script>

    
</head>
<body>
<p><span id="displayId">Click on the squares and sink the boats with the least amount of shots.</span></p>
<p> <span id="victoryText"></span></p>
<table id="gameTable">
        <colgroup> <!-- colgroup allows you to define column properties-->
            <col width="10%"> <col width="10%">
            <col width="10%"> <col width="10%">
            <col width="10%"> <col width="10%">
            <col width="10%"> <col width="10%">
            <col width="10%"> <col width="10%">
        </colgroup>
    <!--alert pop up-->
    <tr class="titleRow" id="titleRow1"> 
        <th id="title" colspan="10">Battleship River Campaign</th> 
        <!--hardcode boats-->
    </tr>
    
    <tr class="landRow" id="landRow1">
        <td colspan=10></td>
     </tr>
     
    <tr class="waterRow" id="waterRow1">
        <td class="square" id="b10"></td>
        <td class="square" id="b11"></td>
        <td class="square" id="b12"></td>
        <td class="square" id="b13"></td>
        <td class="square" id="b14"></td>
        <td class="square" id="b15"></td>
        <td class="square" id="b16"></td>
        <td class="square" id="b17"></td>
        <td class="square" id="b18"></td>
        <td class="square" id="b19"></td>
    </tr>
    
    <tr class="landRow" id="landRow2">
        <td colspan=10></td>
    </tr>
</table>

<br>
<br>

 <div id="graveyard">
<p id="title">Ships Graveyard</p>
<p> <span class="deadShips" id="Battleship"><img src="https://i.imgur.com/NYEsI2j.jpg" height="100" width="100">Destroyer</span></p>
<p> <span class="deadShips" id="Skiff"><img src="https://i.imgur.com/PpXycYV.jpg" height="100" width="100">Canoe</span></p>
</div>


    <input type="button" id="button" value="Reset" onclick="reset(fleet, 'square')"></input>
    
    

</body>

</html>
Jon Drysbach

First, in your global variables, you need to create the variable directly from the DOM element.

var skiff = document.querySelector("#Skiff");
skiff = {name: "Skiff", length:2, spaces:[{hitbox:tinyBox1, hitBefore:false},{hitbox: 
tinyBox2, hitBefore: false}], elem:"Skiff"};

//var battleship ={name:"Battleship", length:3, spaces:[{hitbox:14, hitBefore:false}, 
    {hitbox: 15, hitBefore: false},{hitbox: 16, hitBefore: false}], 
     elem:"Battleship"};
 var battleship = document.querySelector("#Battleship");
 battleship ={name:"Battleship", length:3, spaces:[{hitbox:largeBox1, 
  hitBefore:false},{hitbox: largeBox2, hitBefore: false},{hitbox: largeBox3, 
  hitBefore: false}], elem:"Battleship"};

  var fleet = [];

Then on your window.onLoad function you need to call makeNewBoats() before defining the onLoad fleet.

window.onload = function(){
makeNewBoats();
fleet[0].elem=document.getElementById(fleet[0].name);
fleet[1].elem=document.getElementById(fleet[1].name);

setRowHandlers("square");

}

Related


JavaScript global variable becomes undefined inside function

Ash For some reason JavaScript global variables become undefined inside functions. do not know why. You can copy and run the code. As you can see, the global variable 'target' is defined in the first alert, but then becomes undefined in the function. Here is t

I get an error that the variable inside the function is undefined

Alani Saif In the code below, I have the following lines repeated in the code, so I try to insert them into a function and call them when I need them, but an error occurs and I don't know why: list1=[1000,2000,3000,4000,5000] i=0 c=0.5 n=1000 def func(list1,i,

JavaScript global variable becomes undefined inside function

Ash For some reason JavaScript global variables became undefined inside the function. do not know why. You can copy and run the code. As you can see, the global variable 'target' is defined in the first alert, but then becomes undefined inside the function. He

I get an error that the variable inside the function is undefined

Alani Saif In the code below, I have the following lines repeated in the code, so I tried inserting them into a function and calling them when I need them, but an error occurs and I don't know why: list1=[1000,2000,3000,4000,5000] i=0 c=0.5 n=1000 def func(lis

Why do I get "undefined variable" in my custom PHP function

Lucien Dubois I use PHP Simple Dom Parser . In fact, I created a test for each tag I want to test like this: if(count($html->find('section')) == 0){ echo '<p class="pstatus bg-danger"><span class="glyphicon glyphicon-remove"></span>Aucune balise sémantique sec

Why do I get "undefined variable" in my custom PHP function

Lucien Dubois I use PHP Simple Dom Parser . In fact, I created a test for each tag I want to test like this: if(count($html->find('section')) == 0){ echo '<p class="pstatus bg-danger"><span class="glyphicon glyphicon-remove"></span>Aucune balise sémantique sec

I get an error that the variable inside the function is undefined

Alani Saif In the code below, I have the following lines repeated in the code, so I try to insert them into a function and call them when I need them, but an error occurs and I don't know why: list1=[1000,2000,3000,4000,5000] i=0 c=0.5 n=1000 def func(list1,i,

JavaScript global variable becomes undefined inside function

Ash For some reason JavaScript global variables became undefined inside the function. do not know why. You can copy and run the code. As you can see, the global variable 'target' is defined in the first alert, but then becomes undefined inside the function. He

I get an error that the variable inside the function is undefined

Alani Saif In the code below, I have the following lines repeated in the code, so I try to insert them into a function and call them when I need them, but an error occurs and I don't know why: list1=[1000,2000,3000,4000,5000] i=0 c=0.5 n=1000 def func(list1,i,

I get an error that the variable inside the function is undefined

Alani Saif In the code below, I have the following lines repeated in the code, so I try to insert them into a function and call them when I need them, but an error occurs and I don't know why: list1=[1000,2000,3000,4000,5000] i=0 c=0.5 n=1000 def func(list1,i,