Hi 🤓 Cảm ơn bạn đã ghé thăm blog này, nếu những bài viết trên blog giúp ích cho bạn. Bạn có thể giúp blog hiển thị quảng cáo bằng cách tạm ngừng ad blocker 😫 và để giúp blog duy trì hoạt động nếu bạn muốn.
Cảm ơn bạn!

Khi thao tác DOM với JavaScript, các bạn có thể đã gặp những firstChild, firstElementChild, lastChildlastElementChild. Đây là những thuộc tính nếu không phân biệt được chúng, sẽ dẫn đến việc sử dụng không cho kết quả như mong muốn. Cùng xem chúng khác nhau ở đâu trong bài viết này nhé!

firstChild vs firstElementChild JavaScript

firstChildfirstElementChild là hai thuộc tính read-only, kết quả trả về ở một số trường hợp sẽ không giống nhau, xem ví dụ dưới đây để hiểu hơn nhé ^^.

<body>
  <div class="homiedev-data"></div>

  <script>
    const homiedevEle = document.querySelector(".homiedev-data");

    console.log(homiedevEle.firstChild); // null
    console.log(homiedevEle.firstElementChild); // null
  </script>
</body>

Kết quả cả hai thuộc tính đều trả về null là vì phần tử homiedevEle không chứa bất kì node con nào ^^.

Tuy nhiên nếu ta thêm một khoảng trắng vào homiedevEle thì kết quả sẽ như sau.

<body>
  <div class="homiedev-data"> </div>

  <script>
    const homiedevEle = document.querySelector(".homiedev-data");

    console.log(homiedevEle.firstChild); // " " => một khoảng trắng
    console.log(homiedevEle.firstElementChild); // null
  </script>
</body>

Ta thấy thuộc tính firstChild cho kết quả là " ", vì thuộc tính này trả về bất kỳ loại node nào là node con đầu tiên của homiedevEle. Node là tên chung cho bất kỳ loại object trong DOM, node có nhiều kiểu, một node có thể là element node, text node, comment node,...

Ở ví dụ trên, ta có thể thấy firstChild trả về một text node. Với firstElementChild, nó trả về element node con đầu tiên của homiedevEle, các bạn có thể thấy không có element nào nên kết quả là null.

Thông thường nếu sử dụng console.log(homiedevEle.firstChild); nó sẽ trả về giá trị " ". Ta có thể chuyển sang dạng JavaScript object bằng cách sử dụng format specifiers.

// console.log(homiedevEle.firstChild); kết quả: " "
// console.log('%O', homiedevEle.firstChild); 

Sử dụng %O ta sẽ nhận được kết quả là text node dưới dạng object.

{
    data: " ",
    firstChild: null,
    isConnected: true,
    lastChild: null,
    length: 1,
    nextElementSibling: null,
    nextSibling: null,
    nodeName: "#text",
    nodeType: 3,
    nodeValue: " ",
    // còn nhiều thuộc tính khác
};

Nếu ta thêm một element node cho homiedevEle thì kết quả của firstChildfirstElementChild sẽ là gì? các bạn nghĩ thử và xem kết quả nhé.

<body>
    <div class="homiedev-data">
      <span>URL: </span>
      <a href="https://homiedev.com">Homiedev</a>
    </div>

    <script>
      const homiedevEle = document.querySelector(".homiedev-data");

      // homiedevEle.firstChild) => #text object
      // homiedevEle.firstElementChild => <span>URL: </span>
    </script>
</body>

Khi sử dụng firstChild trong ví dụ trên, ở console ta nhận được #text object, lý do là vì ta đã cho <span>URL: </span> xuống dòng mới và thêm một vài khoảng trống so với đầu dòng, lúc này một text node đã được thêm vào, nhìn nó thế này "\n      ". Và như vậy đây sẽ là first child của homiedevEle khi sử dụng thuộc tính firstChild. Với firstElementChild ta nhận được element <span>URL: </span>, vì đây là một element node và nó là element con đầu tiên của homiedevEle.

Giả sử ta không thêm khoảng trắng (whitespace) giữa thẻ <div class="homiedev-data"><span>URL: </span> thì giá trị của firstChildfirstElementChild là giống nhau.

<body>
    <div class="homiedev-data"><span>URL: </span>
      <a href="https://homiedev.com">Homiedev</a>
    </div>

    <script>
      console.log(homiedevEle.firstChild === homiedevEle.firstElementChild); // true
    </script>
</body>

firstChild trả về bất kỳ loại node nào là node con của homiedevEle, cho nên trong trường hợp này, nó cho cùng kết quả với firstElementChild là node element <span>URL: </span>.

👉 Nếu so sánh lastChild vs lastElementChild thì cũng tương tự như firstChild vs firstElementChild, chúng chỉ khác ở điểm lastChild sẽ trả về bất kỳ loại node nào là con cuối của parent element, lastElementChild thì trả về element node cuối của parent element ^^.


Như vậy là chúng ta đã tìm hiểu xong sự khác nhau giữa firstChild vs firstElementChild, tương tự với lastChild vs lastElementChild. Nếu có bất kỳ thắc mắc nào với nội dung liên quan, các bạn có thể để lại bình luận bên dưới nhé 😃.

Cảm ơn các bạn đã đọc bài viết, chúc các bạn học tốt 🎉.

Có thể bạn thích ⚡
homiedev
About Me

Hi, I'm @devnav. Một người thích chia sẻ kiến thức, đặc biệt là về Frontend 🚀. Trang web này được tạo ra nhằm giúp các bạn học Frontend hiệu quả hơn 🎉😄.

Chúc các bạn tìm được kiến thức hữu ích trong blog này 😁😁.