Chen Deng-Ta Chen Deng-Ta - 2 months ago 8
Javascript Question

Understanding the procedure in the execution of javascript

I am trying to understand the running procedure of JavaScript, but stuck. First question, in line 32 of the Example in https://api.jquery.com/jQuery.each/ , why the script will

Will stop running after "three"
?

Second question, which is related to jQuery: array[i].children() is not a function, I update the code as follows:



var removeElements = function(text, selector) {
var wrapped = $("<div>" + text + "</div>");
wrapped.find(selector).remove();
return wrapped.html();
}

var $fRef = $(".footnoteRef");
for (var i = 0; i < $fRef.length; i++) {
var sup = $fRef.children("sup")[i];
//sup.setAttribute('fnID', $fRef[i].getAttribute("href").substring(1));
var fnT = removeElements(document.getElementById($fRef[i].getAttribute("href").substring(1)).innerHTML, "a");
sup.onmouseover = function(event) {
var fnTip = document.getElementById('fnTip');
if (fnTip) fnTip.parentNode.removeChild(fnTip);
var pTip = document.createElement('div');
//pTip.innerHTML = removeElements(document.getElementById(this.getAttribute('fnID')).innerHTML,"a");
pTip.innerHTML = fnT;
pTip.id = 'fnTip';
pTip.style.position = 'absolute';
pTip.style.left = (event.pageX - 180) + 'px';
pTip.style.top = (event.pageY + 20) + 'px';
pTip.style.width = '360px';
pTip.style.textIndent = '2em';
pTip.style.textAlign = 'left';
pTip.style.backgroundColor = '#FFFFE0';
pTip.style.border = '1px solid #636363';
pTip.style.padding = '5px';
pTip.style.fontSize = '12px';
pTip.style.lineHeight = '1.8';
pTip.style.borderRadius = '5px';
document.body.appendChild(pTip);
};

sup.onmouseout = function(event) {
var fnTip = document.getElementById('fnTip');
if (fnTip) fnTip.parentNode.removeChild(fnTip);
};
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Baryonyx was a theropod dinosaur of the early Cretaceous Period, about 130–125 million years ago<a href="#fn1" class="footnoteRef" id="fnref1"><sup>1</sup></a>. An identifying specimen of the genus was discovered in 1983 in Surrey, England; fragmentary
specimens<a href="#fn2" class="footnoteRef" id="fnref2"><sup>2</sup></a> were later discovered in other parts of the United Kingdom and Iberia. Meaning "heavy claw", Baryonyx refers to the animal's very large claw (31 cm or 12 in) on the first finger.
The 1983 specimen<a href="#fn3" class="footnoteRef" id="fnref3"><sup>3</sup></a> is one of the most complete theropod skeletons from the UK, and its discovery attracted media attention.</p>

<div class="footnotes">
<hr>
<ol>
<li id="fn1">
<p>Baryonyx caught and held its prey primarily with its strong forelimbs and large claws.<a href="#fnref1">↩</a>
</p>
</li>
<li id="fn2">
<p>The creature lived near bodies of water, in areas where other theropod, ornithopod, and sauropod dinosaurs have also been found. <a href="#fnref2">↩</a>
</p>
</li>
<li id="fn3">
<p>It had a long, low, bulbous snout and narrow, many-toothed jaws, which have been compared to gharial jaws.<a href="#fnref3">↩</a>
</p>
</li>
</ol>
</div>





When the mouse is over the footnote symbol superscript 1 and 2, the tool-tip shows the content of footnote 3. Why not show its own footnote?

I am puzzled.

Answer

Question 1

First question, in line 32 of the Example in https://api.jquery.com/jQuery.each/ , why the script will Will stop running after "three"?

Because each stops running when you return false. The line

return ( val !== "three" );

Will return false, once the iteration reaches the string "three" (because "three" !== "three" is false)

If you read the documentation slightly above that code sample, it says:

We can break the $.each() loop at a particular iteration by making the callback function return false. Returning non-false is the same as a continue statement in a for loop; it will skip immediately to the next iteration.


Question 2

When the mouse is over the footnote symbol superscript 1 and 2, the tool-tip shows the content of footnote 3. Why not show its own footnote?

The reason for this is the common closure inside loops problem in JavaScript.

When you look at this portion of your code:

for (var i = 0; i < $fRef.length; i++) {
  // ...

  var fnT = // ... here you create a fnT for each i
  sup.onmouseover = function(event) {
    pTip.innerHTML = fnT; // this happens when the loop is finished, so its always the last fnT

  // ...

What is happening is that the loop is iterating and storing stuff in fnT. Then, the loop finishes, the last fnT is the third one. Some time later you hover over the sup and it shows the fnT it has access to, which is still the third one.

The way you would solve this is to extract the onmouseover listener into its own function and you pass the current fnT into that function. This way, each listener has access to the proper fnT.

for (var i = 0; i < $fRef.length; i++) {
  // ...

  var fnT = // ... here you create your fnT
  addListeners(sup, fnt);
}

function addListeners(sup, fnT) {
  sup.onmouseover = function(event) {
    // ...
    pTip.innerHTML = fnT; // here each listener gets a proper fnT because we pass it in on every loop iteration
    // ...
  }

  sup.onmouseout = function(event) {
    // ...
  }
}

Example the code bellow for a running example

var removeElements = function(text, selector) {
  var wrapped = $("<div>" + text + "</div>");
  wrapped.find(selector).remove();
  return wrapped.html();
}

var $fRef = $(".footnoteRef");
for (var i = 0; i < $fRef.length; i++) {
  var sup = $fRef.children("sup")[i];
  var fnT = removeElements(document.getElementById($fRef[i].getAttribute("href").substring(1)).innerHTML, "a");
  addListeners(sup, fnT);
}

function addListeners(sup, fnT) {
  sup.onmouseover = function(event) {
    var fnTip = document.getElementById('fnTip');
    if (fnTip) fnTip.parentNode.removeChild(fnTip);
    var pTip = document.createElement('div');
    pTip.innerHTML = fnT;
    pTip.id = 'fnTip';
    pTip.style.position = 'absolute';
    pTip.style.left = (event.pageX - 180) + 'px';
    pTip.style.top = (event.pageY + 20) + 'px';
    pTip.style.width = '360px';
    pTip.style.textIndent = '2em';
    pTip.style.textAlign = 'left';
    pTip.style.backgroundColor = '#FFFFE0';
    pTip.style.border = '1px solid #636363';
    pTip.style.padding = '5px';
    pTip.style.fontSize = '12px';
    pTip.style.lineHeight = '1.8';
    pTip.style.borderRadius = '5px';
    document.body.appendChild(pTip);
  };

  sup.onmouseout = function(event) {
    var fnTip = document.getElementById('fnTip');
    if (fnTip) fnTip.parentNode.removeChild(fnTip);
  };
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Baryonyx was a theropod dinosaur of the early Cretaceous Period, about 130–125 million years ago<a href="#fn1" class="footnoteRef" id="fnref1"><sup>1</sup></a>. An identifying specimen of the genus was discovered in 1983 in Surrey, England; fragmentary
  specimens
  <a href="#fn2" class="footnoteRef" id="fnref2"><sup>2</sup></a> were later discovered in other parts of the United Kingdom and Iberia. Meaning "heavy claw", Baryonyx refers to the animal's very large claw (31 cm or 12 in) on the first finger. The 1983
  specimen<a href="#fn3" class="footnoteRef" id="fnref3"><sup>3</sup></a> is one of the most complete theropod skeletons from the UK, and its discovery attracted media attention.</p>

<div class="footnotes">
  <hr>
  <ol>
    <li id="fn1">
      <p>Baryonyx caught and held its prey primarily with its strong forelimbs and large claws.<a href="#fnref1">↩</a>
      </p>
    </li>
    <li id="fn2">
      <p>The creature lived near bodies of water, in areas where other theropod, ornithopod, and sauropod dinosaurs have also been found. <a href="#fnref2">↩</a>
      </p>
    </li>
    <li id="fn3">
      <p>It had a long, low, bulbous snout and narrow, many-toothed jaws, which have been compared to gharial jaws.<a href="#fnref3">↩</a>
      </p>
    </li>
  </ol>
</div>