ID phần tử được đặt tên có thể được tham chiếu dưới dạng Thông tin dữ liệu PlatoBlockchain của JavaScript Globals. Tìm kiếm dọc. Ái.

ID phần tử được đặt tên có thể được tham chiếu như JavaScript Globals

Bạn có biết rằng các phần tử DOM có ID có thể truy cập được trong JavaScript dưới dạng các biến toàn cục không? Đó là một trong những thứ đã tồn tại mãi mãi, nhưng tôi thực sự đang tìm hiểu về nó lần đầu tiên.

Nếu đây là lần đầu tiên bạn nghe về nó, hãy chuẩn bị tinh thần! Chúng ta có thể thấy nó hoạt động đơn giản bằng cách thêm ID vào một phần tử trong HTML:

Thông thường, chúng tôi sẽ xác định một biến mới bằng cách sử dụng querySelector("#cool") or getElementById("cool") để chọn phần tử đó:

var el = querySelector("#cool");

Nhưng chúng tôi thực sự đã có quyền truy cập vào #cool không có giàn khoan đó:

Vì vậy, bất kỳ id - hoặc là name , vì vấn đề đó - trong HTML có thể được truy cập trong JavaScript bằng cách sử dụng window[ELEMENT_ID]. Một lần nữa, điều này không chính xác là "mới" nhưng nó thực sự không phổ biến.

Như bạn có thể đoán, truy cập phạm vi toàn cầu với các tham chiếu được đặt tên không phải là ý tưởng tuyệt vời nhất. Một số người đã gọi đây là "kẻ gây ô nhiễm phạm vi toàn cầu." Chúng ta sẽ tìm hiểu lý do tại sao lại như vậy, nhưng trước tiên…

Một số bối cảnh

Cách tiếp cận này là được nêu trong đặc tả HTML, nơi nó được mô tả là “quyền truy cập được đặt tên trên Window sự vật."

Internet Explorer là người đầu tiên triển khai tính năng này. Tất cả các trình duyệt khác cũng đã thêm nó. Gecko là trình duyệt duy nhất vào thời điểm đó không hỗ trợ trực tiếp ở chế độ tiêu chuẩn, thay vào đó, Gecko đã chọn biến nó thành một tính năng thử nghiệm. Có chút do dự khi thực hiện nó, nhưng nó tiến lên phía trước nhân danh khả năng tương thích của trình duyệt (Gecko thậm chí còn cố gắng thuyết phục WebKit để chuyển nó ra khỏi chế độ tiêu chuẩn) và cuối cùng chuyển sang chế độ tiêu chuẩn trong Firefox 14.

Một điều có thể không được nhiều người biết đến là các trình duyệt đã phải thực hiện một số biện pháp phòng ngừa - với các mức độ thành công khác nhau - để đảm bảo các hình cầu được tạo ra không làm hỏng trang web. Một trong những biện pháp như vậy là…

Đổ bóng thay đổi

Có lẽ phần thú vị nhất của tính năng này là các tham chiếu phần tử được đặt tên không phủ bóng các biến toàn cầu hiện có. Vì vậy, nếu một phần tử DOM có id đã được xác định là toàn cầu, nó sẽ không ghi đè lên cái hiện có. Ví dụ:


  
    window.foo = "bar";
  


  
I won't override window.foo
console.log(window.foo); // Prints "bar"

Và điều ngược lại cũng đúng:

I will be overridden :(
window.foo = "bar"; console.log(window.foo); // Prints "bar"

Hành vi này là cần thiết vì nó vô hiệu hóa các ghi đè nguy hiểm như

, nếu không sẽ tạo ra xung đột bằng cách làm mất hiệu lực của alert API. Kỹ thuật bảo vệ này rất có thể là lý do tại sao bạn - nếu bạn giống tôi - lần đầu tiên học về điều này.

Trường hợp chống lại các quả cầu được đặt tên

Trước đó, tôi đã nói rằng việc sử dụng các phần tử được đặt tên chung làm tham chiếu có thể không phải là ý tưởng tuyệt vời nhất. Có rất nhiều lý do cho điều đó, TJ VanToll đã trình bày một cách tuyệt vời trên blog của anh ấy và tôi sẽ tóm tắt ở đây:

  • Nếu DOM thay đổi, thì tham chiếu cũng vậy. Điều đó làm cho một số thực sự "giòn" (thuật ngữ của thông số kỹ thuật đối với nó) mã trong đó mối quan tâm tách biệt giữa HTML và JavaScript có thể là quá nhiều.
  • Tham chiếu tình cờ là quá dễ dàng. Một lỗi đánh máy đơn giản rất có thể kết thúc tham chiếu đến một toàn cầu được đặt tên và mang lại cho bạn kết quả bất ngờ.
  • Nó được triển khai khác nhau trong các trình duyệt. Ví dụ: chúng ta có thể truy cập vào một mỏ neo với id - ví dụ - nhưng một số trình duyệt (cụ thể là Safari và Firefox) trả về ReferenceError trong bảng điều khiển.
  • Nó có thể không trả lại những gì bạn nghĩ. Theo thông số kỹ thuật, khi có nhiều trường hợp của cùng một phần tử được đặt tên trong DOM - giả sử, hai trường hợp của

    - trình duyệt sẽ trả về một HTMLCollection với một mảng các trường hợp. Tuy nhiên, Firefox chỉ trả về phiên bản đầu tiên. Sau đó một lần nữa, thông số kỹ thuật nói chúng ta nên sử dụng một trường hợp của một id trong cây của một phần tử nào đó. Nhưng làm như vậy sẽ không ngăn một trang hoạt động hoặc bất cứ điều gì tương tự.

  • Có thể có một chi phí hiệu suất? Ý tôi là, trình duyệt phải tạo danh sách các tham chiếu đó và duy trì nó. Một vài người đã chạy thử nghiệm trong chuỗi StackOverflow này, nơi các quả cầu được đặt tên thực sự là hiệu quả hơn trong một bài kiểm trakém hiệu quả hơn trong một thử nghiệm gần đây hơn.

Xem xét bổ sung

Giả sử chúng tôi loại bỏ những lời chỉ trích chống lại việc sử dụng các hình cầu được đặt tên và vẫn sử dụng chúng. Tất cả đều tốt. Nhưng có một số điều bạn có thể muốn cân nhắc khi làm.

polyfill

Nghe có vẻ như là edge-case-y, các loại kiểm tra toàn cục này là một yêu cầu thiết lập điển hình cho polyfills. Kiểm tra ví dụ sau, nơi chúng tôi đặt cookie bằng cách sử dụng CookieStore API, polyfilling nó trên các trình duyệt chưa hỗ trợ nó:


  
  
    // Polyfill the CookieStore API if not yet implemented.
    // https://developer.mozilla.org/en-US/docs/Web/API/CookieStore
    if (!window.cookieStore) {
      window.cookieStore = myCookieStorePolyfill;
    }
    cookieStore.set("foo", "bar");
  

Mã này hoạt động hoàn toàn tốt trong Chrome, nhưng gây ra lỗi sau trong Safari:

TypeError: cookieStore.set is not a function

Safari thiếu hỗ trợ cho CookieStore API kể từ khi viết bài này. Do đó, polyfill không được áp dụng vì img ID phần tử tạo ra một biến toàn cục xung đột với cookieStore toàn cầu

Cập nhật API JavaScript

Chúng tôi có thể lật ngược tình huống và tìm ra một vấn đề khác trong đó các bản cập nhật cho công cụ JavaScript của trình duyệt có thể phá vỡ các tham chiếu chung của phần tử được đặt tên.

Ví dụ:


  
  
    window.BarcodeDetector.focus();
  

Tập lệnh đó lấy một tham chiếu đến phần tử đầu vào và gọi focus() trên đó. Nó hoạt động chính xác. Tuy nhiên, chúng tôi không biết làm thế nào Dài nó sẽ tiếp tục hoạt động.

Bạn thấy đấy, biến toàn cục mà chúng tôi đang sử dụng để tham chiếu đến phần tử đầu vào sẽ ngừng hoạt động ngay khi các trình duyệt bắt đầu hỗ trợ BarcodeDetector API. Tại thời điểm đó, window.BarcodeDetector toàn cầu sẽ không còn là tham chiếu đến phần tử đầu vào và .focus() sẽ ném một “window.BarcodeDetector.focus không phải là một chức năng ”lỗi.

Phần thưởng: Không phải tất cả các phần tử được đặt tên đều tạo ra các tham chiếu toàn cầu

Bạn muốn nghe điều gì đó vui nhộn? Để tăng thêm sự xúc phạm cho thương tích, các phần tử được đặt tên chỉ có thể truy cập được dưới dạng biến toàn cục nếu tên không chứa gì ngoài chữ cái. Trình duyệt sẽ không tạo tham chiếu toàn cục cho một phần tử có ID chứa các ký tự và số đặc biệt, như hello-worlditem1.

Kết luận

Hãy tóm tắt cách chúng tôi đến đây:

  • Tất cả các trình duyệt chính đều tự động tạo các tham chiếu chung đến từng phần tử DOM với id (hoặc, trong một số trường hợp, name thuộc tính).
  • Việc truy cập các phần tử này thông qua các tham chiếu toàn cầu của chúng là không đáng tin cậy và có khả năng nguy hiểm. Sử dụng querySelector or getElementById thay thế.
  • Vì các tham chiếu chung được tạo tự động, chúng có thể có một số tác dụng phụ đối với mã của bạn. Đó là lý do chính đáng để tránh sử dụng id thuộc tính trừ khi bạn thực sự cần nó.

Vào cuối ngày, có lẽ bạn nên tránh sử dụng các hình cầu có tên trong JavaScript. Tôi đã trích dẫn thông số kỹ thuật trước đó về cách nó dẫn đến mã "giòn", nhưng đây là toàn bộ văn bản để hướng điểm về nhà:

Theo nguyên tắc chung, dựa vào điều này sẽ dẫn đến mã giòn. Những ID nào kết thúc ánh xạ tới API này có thể thay đổi theo thời gian, chẳng hạn như các tính năng mới được thêm vào nền tảng web. Thay vì điều này, hãy sử dụng document.getElementById() or document.querySelector().

Tôi nghĩ rằng bản thân thông số kỹ thuật HTML khuyến nghị tránh xa tính năng này đã tự nói lên điều đó.

Dấu thời gian:

Thêm từ Thủ thuật CSS