Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why For..in(loop) alway breaks the function where it stay in?

Haizz. Hello guys..

I'm learning Web Dev in: https://www.w3schools.com/.

I did a very simple homework here: https://www.w3schools.com/howto/tryit.asp?filename=tryhow_js_tabs

```
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body {font-family: Arial;}

/* Style the tab */
.tab {
  overflow: hidden;
  border: 1px solid #ccc;
  background-color: #f1f1f1;
}

/* Style the buttons inside the tab */
.tab button {
  background-color: inherit;
  float: left;
  border: none;
  outline: none;
  cursor: pointer;
  padding: 14px 16px;
  transition: 0.3s;
  font-size: 17px;
}

/* Change background color of buttons on hover */
.tab button:hover {
  background-color: #ddd;
}

/* Create an active/current tablink class */
.tab button.active {
  background-color: #ccc;
}

/* Style the tab content */
.tabcontent {
  display: none;
  padding: 6px 12px;
  border: 1px solid #ccc;
  border-top: none;
}
</style>
</head>
<body>

<h2>Tabs</h2>
<p>Click on the buttons inside the tabbed menu:</p>

<div class="tab">
  <button class="tablinks" onclick="openCity(event, 'London')">London</button>
  <button class="tablinks" onclick="openCity(event, 'Paris')">Paris</button>
  <button class="tablinks" onclick="openCity(event, 'Tokyo')">Tokyo</button>
</div>

<div id="London" class="tabcontent">
  <h3>London</h3>
  <p>London is the capital city of England.</p>
</div>

<div id="Paris" class="tabcontent">
  <h3>Paris</h3>
  <p>Paris is the capital of France.</p> 
</div>

<div id="Tokyo" class="tabcontent">
  <h3>Tokyo</h3>
  <p>Tokyo is the capital of Japan.</p>
</div>

<script>
function openCity(evt, cityName) {
  var i, tabcontent, tablinks;
  tabcontent = document.getElementsByClassName("tabcontent");
  for (i = 0; i < tabcontent.length; i++) {
    tabcontent[i].style.display = "none";
  }
  tablinks = document.getElementsByClassName("tablinks");
  for (i = 0; i < tablinks.length; i++) {
    tablinks[i].className = tablinks[i].className.replace(" active", "");
  }
  document.getElementById(cityName).style.display = "block";
  evt.currentTarget.className += " active";
}
</script>

</body>
</html>
```

But.... When I try to exchange the traditional for-loop to for..in loop. It not work?

Ex. for (i in tabcontent) { tabcontent[i].style.display = "none"; }

After many time I try to make it work. I've found that all statement follow the first for..in loop will be skip !!!???? It mean the Function will auto-break after a for..in loop. The first for..in loop work as normal, but the rest statement after it is simply skip. The Function break at this point?

If anyone knew this problem please help me to understand it. X__X

like image 675
La Mort Avatar asked Dec 30 '19 15:12

La Mort


People also ask

Why do we use break in for loop?

The purpose the break statement is to break out of a loop early. For example if the following code asks a use input a integer number x. If x is divisible by 5, the break statement is executed and this causes the exit from the loop.

DO for loops always terminate?

The “for” loop Executes once upon entering the loop. Checked before every loop iteration. If false, the loop stops. Runs again and again while the condition is truthy.

Where do you put a break in for a loop?

You'll put the break statement within the block of code under your loop statement, usually after a conditional if statement.

Why should break and continue be always used with an if embedded in a while or for loop?

A break statement, when used inside the loop, will terminate the loop and exit. If used inside nested loops, it will break out from the current loop. A continue statement will stop the current execution when used inside a loop, and the control will go back to the start of the loop.


2 Answers

The "auto-break" you're seeing is an uncaught exception breaking execution – you should have your browser's console open to see any errors that occur and are uncaught.

That change yields an

Uncaught TypeError: Cannot set property 'display' of undefined
    at openCity (<anonymous>:6:33)
    at HTMLButtonElement.onclick (tryit.asp?filename=tryhow_js_tabs:1)

since for..in loops over properties of objects, not array elements as you imagine, and i ends up (as evidenced by console.log(i)) being 0, 1, 2, and then finally length, and tabcontent.length has no style property, so the equivalent of

tabcontent.length.style.display = ...

naturally fails.

like image 147
AKX Avatar answered Sep 19 '22 16:09

AKX


You can go with the for in loop. The loop will give you indexes but because you have not converted it to an array you get some extra (unwanted properties) hence the error.

The key is to make the conversion, after that you are safe with the for in loop:
let tabContent = Array.from(document.getElementsByClassName("tabcontent"))

Example proof: https://jsfiddle.net/sqfgb0k6/

<!DOCTYPE html>
<html>

  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
      body {
        font-family: Arial;
      }

      /* Style the tab */
      .tab {
        overflow: hidden;
        border: 1px solid #ccc;
        background-color: #f1f1f1;
      }

      /* Style the buttons inside the tab */
      .tab button {
        background-color: inherit;
        float: left;
        border: none;
        outline: none;
        cursor: pointer;
        padding: 14px 16px;
        transition: 0.3s;
        font-size: 17px;
      }

      /* Change background color of buttons on hover */
      .tab button:hover {
        background-color: #ddd;
      }

      /* Create an active/current tablink class */
      .tab button.active {
        background-color: #ccc;
      }

      /* Style the tab content */
      .tabcontent {
        display: none;
        padding: 6px 12px;
        border: 1px solid #ccc;
        border-top: none;
      }

    </style>
  </head>

  <body>

    <h2>Tabs</h2>
    <p>Click on the buttons inside the tabbed menu:</p>

    <div class="tab">
      <button class="tablinks" onclick="openCity(event, 'London')">London</button>
      <button class="tablinks" onclick="openCity(event, 'Paris')">Paris</button>
      <button class="tablinks" onclick="openCity(event, 'Tokyo')">Tokyo</button>
    </div>

    <div id="London" class="tabcontent">
      <h3>London</h3>
      <p>London is the capital city of England.</p>
    </div>

    <div id="Paris" class="tabcontent">
      <h3>Paris</h3>
      <p>Paris is the capital of France.</p>
    </div>

    <div id="Tokyo" class="tabcontent">
      <h3>Tokyo</h3>
      <p>Tokyo is the capital of Japan.</p>
    </div>

    <script>
      function openCity(evt, cityName) {
        let i, tablinks
        let tabContent = Array.from(document.getElementsByClassName("tabcontent"))
        for (let i in tabContent) {
          tabContent[i].style.display = "none";
        }
        tablinks = document.getElementsByClassName("tablinks");
        for (let i in tabContent) {
          tablinks[i].className = tablinks[i].className.replace(" active", "");
        }
        document.getElementById(cityName).style.display = "block";
        evt.currentTarget.className += " active";
      }

    </script>

  </body>

</html>
like image 25
Eugen Sunic Avatar answered Sep 18 '22 16:09

Eugen Sunic