SitePoint Sponsor

User Tag List

Results 1 to 4 of 4
  1. #1
    SitePoint Member
    Join Date
    Jun 2012
    Posts
    19
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Please help me understand this JavaScript function...

    This function is from JavaScript:The Definitive Guide - 6th Edition, page 374:

    Code:
    /**
    * Return the nth element child of e, or null if it doesn't have one.
    * Negative values of n count from the end. 0 means the first child, but
    * -1 means the last child, -2 means the second to last, and so on.
    */
    function child(e, n) {
      if (e.children) { // If children array exists
      if (n < 0) n += e.children.length; // Convert negative n to array index
      if (n < 0) return null; // If still negative, no child
      return e.children[n]; // Return specified child
      }
      // If e does not have a children array, find the first child and count
      // forward or find the last child and count backwards from there.
      if (n >= 0) { // n is non-negative: count forward from the first child
      // Find the first child element of e  <<<---------------------------  This is where code starts to get confusing to me
      if (e.firstElementChild) e = e.firstElementChild;  //    <<<----------- e.children must not exists if we are executing this line of code, so why check for Elements on e again? Maybe he meant to check 'firstChild'?
        else {  <<<--------------------------- if author knows at this point that e argument is not actually an element
        for(e = e.firstChild; e && e.nodeType !== 1; e = e.nextSibling) //  <<<----------- Why does he look for an element here by running loop until nodeType !== 1 ? TextNodes and CommentNodes will never contain Elements
        /* empty */;
        }
        return sibling(e, n); // Return the nth sibling of the first child
      }
      else { // n is negative, so count backwards from the end
      if (e.lastElementChild) e = e.lastElementChild;
      else {
      for(e = e.lastChild; e && e.nodeType !== 1; e=e.previousSibling)
      /* empty */;
      }
      return sibling(e, n+1); // +1 to convert child -1 to sib 0 of last
      }
    }
    At the line of JavaScript code that I have pointed out above the author has already determined that the element passed is not actually an element so it must then be a TextNode(3) or CommentNode(8). So why does he run a loop looking for a NodeType == 1 on the childNodes of argument e? I may be missing something here but if somebody could show me what it is, that would be great. Thanks for reading.
    Last edited by ig-88; Jul 31, 2012 at 09:27. Reason: because I proofread after I post

  2. #2
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,688
    Mentioned
    100 Post(s)
    Tagged
    4 Thread(s)
    This is the code in question (braces added);

    Code:
    if (e.firstElementChild) {
        e = e.firstElementChild;
    } else {
        for(e = e.firstChild; e && e.nodeType !== 1; e = e.nextSibling) {
            ...
        }
    }
    That loop is going to keep on looping through the next siblings. Eventually you will get to the end of the siblings, at which point e will be null.
    That is why the check - it's checking to see if you've gone past the last sibling.

    The reason for that code though, is for if the web browser doesn't know about the firstElementChild property. If the web browser doesn't support that technique, the for loop is an old-fashioned and slightly slower, but reliable way to achieve it instead.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  3. #3
    SitePoint Member
    Join Date
    Jun 2012
    Posts
    19
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by paul_wilkins View Post
    This is the code in question (braces added);

    Code:
    if (e.firstElementChild) {
        e = e.firstElementChild;
    } else {
        for(e = e.firstChild; e && e.nodeType !== 1; e = e.nextSibling) {
            ...
        }
    }
    That loop is going to keep on looping through the next siblings. Eventually you will get to the end of the siblings, at which point e will be null.
    That is why the check - it's checking to see if you've gone past the last sibling.

    The reason for that code though, is for if the web browser doesn't know about the firstElementChild property. If the web browser doesn't support that technique, the for loop is an old-fashioned and slightly slower, but reliable way to achieve it instead.
    But unless I am mistaken there is a difference between when using firstElementChild versus using firstChild. The first property finds "only" Element objects. The second property finds any Nodes regardless of their nodeType. The author first looks for an Element object. Failing that his else loop only breaks when he reaches the end of the children or when the loop finds the firstChild that is an element(nodeType==1). Why if he has already determined that there is no firstElementChild would he look for it again in an else loop? It doesn't make sense.

  4. #4
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,688
    Mentioned
    100 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by ig-88 View Post
    But unless I am mistaken there is a difference between when using firstElementChild versus using firstChild. The first property finds "only" Element objects. The second property finds any Nodes regardless of their nodeType. The author first looks for an Element object. Failing that his else loop only breaks when he reaches the end of the children or when the loop finds the firstChild that is an element(nodeType==1). Why if he has already determined that there is no firstElementChild would he look for it again in an else loop? It doesn't make sense.
    The author desired to get the first child element. Some web browsers have a nice way of doing that with the firstElementChild method.

    This is where you seem to get hung up though. If firstElementChild is not found, that does not necessarily mean that there is no child element to be found. That can also occur when the web browser completely fails to support the firstElementChild method.

    Time for some details. This W3C DOM Compatibility - Traversal page shows that the Firefox 3.0 and IE up to IE8 web browsers do not support the firstElementChild method. So even if there is a child element to be found, those browsers will just completely fail because they do not know what the firstElementChild is.

    It is for those older web browsers that the else case is used.

    Code:
    if (test for browser compatibility) {
        use browser-supported method
    } else {
        use compatibility code to achieve same end-result
    }
    You can see a similar example of compatibility code on the Array forEach documention page
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •