Các phần tử cây DOM có id trở thành biến toàn cục?


364

Làm việc trên một ý tưởng cho trình bao bọc HTMLE bổ sung đơn giản, tôi đã tình cờ tìm thấy những điều sau đây cho Internet Explorer và Chrome :

Đối với một HTMLE bổ sung có ID trong cây DOM, có thể truy xuất div bằng ID của nó làm tên biến. Vì vậy, đối với một div như

<div id="example">some text</div>

trong Internet Explorer 8 và Chrome bạn có thể làm:

alert(example.innerHTML); //=> 'some text'

hoặc là

alert(window['example'].innerHTML); //=> 'some text'

Vì vậy, điều này có nghĩa là mọi phần tử trong cây DOM được chuyển đổi thành một biến trong không gian tên toàn cục? Và nó cũng có nghĩa là người ta có thể sử dụng điều này như một sự thay thế cho getElementByIdphương thức trong các trình duyệt này?



1
@Bergi, bình luận nói rằng không làm điều này bây giờ đã lỗi thời và thậm chí không hợp lệ. Do đó, tôi không thể tìm thấy lý do cụ thể để không sử dụng tính năng này.
ESR

@EdmundReed Bạn có thể muốn đọc lại câu trả lời của câu hỏi được liên kết - đó vẫn là một ý tưởng tồi: " các biến toàn cục được khai báo ngầm " có hại khi không hỗ trợ công cụ và " dẫn đến mã dễ vỡ ". Đừng gọi nó là "tính năng", câu trả lời dưới đây giải thích cách nó chỉ là một lỗi trở thành một phần của tiêu chuẩn vì lý do tương thích.
Bergi

1
@Bergi đủ công bằng, bạn nói đúng. Tôi vẫn nghĩ rằng đó là một tính năng thực sự gọn gàng và chỉ được coi là có vấn đề vì mọi người không biết về nó. Đây là cách tôi hình dung bằng cách sử dụng nó: codepen.io/esr360/pen/weavGE?editors=1000#0
ESR

@EdmundReed Sẽ ít vấn đề hơn nếu bạn không phân tách đúng nội dung và logic. Ngoài ra, tôi khuyên bạn không bao giờ sử dụng các trình xử lý sự kiện nội tuyến hoặc cài đặt các phương thức tùy chỉnh trên các thành phần DOM lạm dụng chúng làm không gian tên (lưu ý rằng đó không phải là "phạm vi").
Bergi

Câu trả lời:


395

Điều được cho là xảy ra là 'các phần tử được đặt tên' được thêm vào dưới dạng các thuộc tính rõ ràng của documentđối tượng. Đây là một ý tưởng thực sự tồi tệ, vì nó cho phép các tên thành phần xung đột với các thuộc tính thực của document.

IE làm cho tình hình tồi tệ hơn bằng cách thêm các phần tử được đặt tên làm thuộc tính của windowđối tượng. Đây là gấp đôi xấu ở chỗ bây giờ bạn phải tránh đặt tên nguyên tố của bạn sau khi bất kỳ thành viên của một trong hai documenthoặc windowđối tượng bạn (hoặc bất kỳ mã thư viện khác trong dự án của bạn) có thể muốn sử dụng.

Nó cũng có nghĩa là các yếu tố này được hiển thị dưới dạng các biến giống như toàn cầu. May mắn thay trong trường hợp này, bất kỳ khai báo toàn cầu varhoặc thực tế nào functiontrong mã của bạn đều che giấu chúng, vì vậy bạn không cần phải lo lắng quá nhiều về việc đặt tên ở đây, nhưng nếu bạn cố gắng gán một biến toàn cục với tên xung đột và bạn quên khai báo nó var, bạn sẽ gặp lỗi trong IE khi nó cố gắng gán giá trị cho chính phần tử đó.

Nó thường được coi là thực hành xấu để bỏ qua var, cũng như dựa vào các yếu tố được đặt tên có thể nhìn thấy trên windowhoặc dưới dạng toàn cầu. Bám sát document.getElementById, được hỗ trợ rộng rãi hơn và ít mơ hồ hơn. Bạn có thể viết một hàm bao bọc tầm thường với một tên ngắn hơn nếu bạn không thích gõ. Dù bằng cách nào, không có điểm nào trong việc sử dụng bộ đệm tra cứu id-to-Element, bởi vì các trình duyệt thường tối ưu hóa getElementByIdcuộc gọi để sử dụng tra cứu nhanh; tất cả những gì bạn nhận được là các vấn đề khi các yếu tố thay đổi idhoặc được thêm / xóa khỏi tài liệu.

Opera đã sao chép IE, sau đó WebKit đã tham gia và bây giờ cả thực tiễn chưa được chuẩn hóa trước đó về việc đưa các yếu tố được đặt tên lên documentcác thuộc tính và thực tiễn chỉ sử dụng IE trước đây windowđang được chuẩn hóa bởi HTML5, cách tiếp cận của nó là tài liệu hóa và chuẩn hóa mọi thực tiễn khủng khiếp gây ra cho chúng tôi bởi các tác giả trình duyệt, khiến chúng trở thành một phần của web mãi mãi. Vì vậy, Firefox 4 cũng sẽ hỗ trợ điều này.

"Các yếu tố được đặt tên" là gì? Bất cứ thứ gì có idvà bất cứ thứ gì nameđược sử dụng cho mục đích 'xác định': đó là, biểu mẫu, hình ảnh, neo và một vài thứ khác, nhưng không phải là các trường hợp không liên quan khác của một namethuộc tính, như tên điều khiển trong trường nhập mẫu, tên tham số trong <param>hoặc loại siêu dữ liệu trong <meta>. 'Xác định namelà những điều nên tránh để ủng hộ id.


5
Đó là một câu trả lời rõ ràng, cảm ơn. Đó không phải là ý tưởng của tôi để bỏ qua document.getEuityById (tốt, như một vấn đề thực tế là tôi sử dụng xpath khi có thể để tìm kiếm các thuộc tính / phần tử hiện nay). Tôi tình cờ thấy cách thực hành (xấu) này đối với các mặt hàng được đặt tên và tò mò không biết nó đến từ đâu. Bạn đã trả lời đủ rồi; bây giờ chúng tôi biết tại sao nó cũng có thể được tìm thấy trong Chrome (webkit).
KooiInc

18
Một ngoại lệ đối với "việc sử dụng namenên tránh" là với <input>, trong đó namethuộc tính đóng vai trò quan trọng trong việc hình thành khóa của các cặp khóa-giá trị để gửi biểu mẫu.
Yahel

7
FYI Firefox chỉ làm điều này khi được đưa vào chế độ quirks.
Lưỡi liềm tươi

4
@yahelc: đó chính xác là sự khác biệt mà tôi đang thực hiện. Không phải là cách sử dụng khác của nametên điều khiển giống như trong các trường nhập mẫu ... Hãy
bobince

13
TẠI SAO!? Có bất cứ điều gì chúng ta có thể làm để ngăn chặn sự điên rồ này? Các chức năng của tôi đã được xác định lại bằng cách tham chiếu đến các phần tử và phải mất một giờ để tôi gỡ lỗi. :(
Farzher

52

Như đã đề cập trong câu trả lời trước, hành vi này được gọi là quyền truy cập được đặt tên trên đối tượng cửa sổ . Giá trị của namethuộc tính cho một số phần tử và giá trị của idthuộc tính cho tất cả các phần tử được cung cấp dưới dạng các thuộc tính của windowđối tượng toàn cục . Chúng được gọi là các yếu tố được đặt tên. Vì windowlà đối tượng toàn cầu trong trình duyệt, mỗi phần tử được đặt tên sẽ có thể truy cập dưới dạng biến toàn cục.

Điều này ban đầu được thêm vào bởi Internet Explorer và cuối cùng được thực hiện bởi tất cả các trình duyệt khác chỉ để tương thích với các trang web phụ thuộc vào hành vi này. Thật thú vị, Gecko (công cụ kết xuất của Firefox) đã chọn chỉ thực hiện điều này ở chế độ quirks , trong khi các công cụ kết xuất khác để nó ở chế độ tiêu chuẩn.

Tuy nhiên, kể từ Firefox 14, Firefox hiện cũng hỗ trợ truy cập có tên trên windowđối tượng ở chế độ tiêu chuẩn. Tại sao họ thay đổi điều này? Hóa ra vẫn còn rất nhiều trang web dựa vào chức năng này trong chế độ tiêu chuẩn. Microsoft thậm chí đã phát hành một bản demo tiếp thị đã làm, ngăn không cho bản demo hoạt động trong Firefox.

Webkit gần đây đã xem xét điều ngược lại , chỉ loại bỏ quyền truy cập có tên trên windowđối tượng sang chế độ quirks. Họ quyết định chống lại nó bằng lý do tương tự như Gecko.

Vì vậy, điên rồ vì dường như hành vi này hiện an toàn về mặt kỹ thuật để sử dụng trong phiên bản mới nhất của tất cả các trình duyệt chính ở chế độ tiêu chuẩn . Nhưng trong khi truy cập được đặt tên có vẻ hơi thuận tiện, nó không nên được sử dụng .

Tại sao? Rất nhiều lý do có thể được tóm tắt trong bài viết này về lý do tại sao các biến toàn cầu là xấu . Nói một cách đơn giản, việc có một loạt các biến toàn cầu bổ sung dẫn đến nhiều lỗi hơn. Giả sử bạn vô tình nhập tên của a varvà tình cờ nhập idmột nút DOM, SURPRISE!

Ngoài ra, mặc dù đã được chuẩn hóa, vẫn còn khá nhiều điểm khác biệt trong việc triển khai truy cập có tên của trình duyệt.

  • IE không chính xác làm cho giá trị của namethuộc tính có thể truy cập được đối với các thành phần của biểu mẫu (đầu vào, chọn, v.v.).
  • Tắc kè và Webkit không chính xác KHÔNG làm cho <a>các thẻ có thể truy cập thông qua namethuộc tính của chúng .
  • Tắc kè xử lý không chính xác nhiều phần tử được đặt tên có cùng tên (nó trả về một tham chiếu đến một nút thay vì một mảng các tham chiếu).

Và tôi chắc chắn sẽ có nhiều hơn nếu bạn thử sử dụng quyền truy cập có tên trên các trường hợp cạnh.

Như đã đề cập trong các câu trả lời khác, sử dụng document.getElementByIdđể có được một tham chiếu đến nút DOM id. Nếu bạn cần lấy một tham chiếu đến một nút bằng cách namesử dụng thuộc tính của nó document.querySelectorAll.

Xin vui lòng, không truyền bá vấn đề này bằng cách sử dụng quyền truy cập có tên trong trang web của bạn. Vì vậy, nhiều nhà phát triển web đã lãng phí thời gian để cố gắng theo dõi hành vi kỳ diệu này . Chúng tôi thực sự cần phải hành động và nhận các công cụ kết xuất để tắt quyền truy cập có tên trong chế độ tiêu chuẩn. Trong ngắn hạn, nó sẽ phá vỡ một số trang web làm những điều xấu, nhưng về lâu dài, nó sẽ giúp đưa web về phía trước.

Nếu bạn quan tâm, tôi sẽ nói về vấn đề này chi tiết hơn trên blog của mình - https://www.tjaugeoll.com/2012/07/19/dom-element-references-as-global-variabled/ .


3
Chỉ cần một lưu ý cho sự cảnh báo rõ ràng với tiền đề rằng "nó không nên được sử dụng". Đó là, "không nên sử dụng KHÔNG GIỚI HẠN bạn tình cờ là một cao bồi mã." Mã cao bồi chỉ cần đi cho nó.
Jeremy Foster

5
@jeremyfoster trừ khi "cao bồi mã" có nghĩa là người sử dụng và tuyên truyền các triển khai không thân thiện với nhà phát triển, tôi hoàn toàn không đồng ý.
Patrick Roberts

2
Một dấu ấn của một cao bồi tốt là nhiều người không đồng ý. Nhưng bây giờ tôi giống như cao bồi triết học hoặc đại loại như thế.
Jeremy Foster

Nhiều người nên sử dụng document.querySelectorAlldocument.querySelectorkhi truy cập DOM. +1 cho đề xuất tốt về việc sử dụng đó. Truy cập các yếu tố bằng bộ chọn chắc chắn là một quá trình hiệu quả hơn.
Travis J

20

Bạn nên bám vào getElementById()trong những trường hợp này, ví dụ:

document.getElementById('example').innerHTML

IE thích kết hợp các yếu tố với name ID các thuộc tính trong không gian tên toàn cầu, vì vậy tốt nhất nên rõ ràng về những gì bạn đang cố gắng để có được.


3

Vâng, họ làm.

Đã thử nghiệm trong Chrome 55, Firefox 50, IE 11, IE Edge 14 và Safari 10
với ví dụ sau:

<!DOCTYPE html>
<html>
<head>
</head>
<body>
  <div id="im_not_particularly_happy_with_that">
    Hello World!
  </div>
  <script>
    im_not_particularly_happy_with_that.innerText = 'Hello Internet!';
  </script>
  <!-- Looking at you W3 HTML5 spec group _ -->
</body>
</html>

http://jsbin.com/mahobinopa/edit?html,output


1
Cũng trong Opera. Tuy nhiên, tôi nghĩ rằng sự phản đối đối với cơ chế này được thể hiện trên trang này được thực hiện rất tốt.
ncmathsadist

1

Câu hỏi sẽ xuất hiện :: "Các thẻ HTML có ID được cung cấp có trở thành các thành phần DOM có thể truy cập toàn cầu không?"

Câu trả lời là CÓ!

Đó là cách nó hoạt động và đó là lý do tại sao ID được W3C giới thiệu bắt đầu bằng: ID của Thẻ HTML trong môi trường tập lệnh được phân tích cú pháp trở thành phần tử DOM Element tương ứng.

Tuy nhiên, Netscape Mozilla đã từ chối tuân thủ (đối với họ xâm nhập) W3C và ngoan cố giữ thuộc tính Name không dùng nữa để tạo sự tàn phá và do đó phá vỡ chức năng Scripting và sự tiện lợi mã hóa do giới thiệu ID duy nhất của W3C mang lại.

Sau khi Netscape Navigator 4.7 fiasco, tất cả các nhà phát triển của họ đã đi vào và xâm nhập vào W3C, trong khi các cộng sự của họ đang thay thế Web bằng các thực tiễn sai và các ví dụ lạm dụng. Buộc sử dụng và tái sử dụng thuộc tính Tên đã không dùng nữa [! Không có nghĩa là duy nhất] ngang bằng với các thuộc tính ID để các tập lệnh sử dụng ID xử lý để truy cập các phần tử DOM cụ thể sẽ bị hỏng!

Và phá vỡ họ đã làm như họ cũng sẽ viết và xuất bản các bài học và ví dụ mã hóa mở rộng [dù sao trình duyệt của họ cũng không nhận ra], document.all.ElementID.propertythay vì ElementID.propertyít nhất làm cho nó không hiệu quả và cung cấp cho trình duyệt nhiều chi phí hơn trong trường hợp nó không đơn giản phá vỡ nó Tên miền HTML bằng cách sử dụng cùng một mã thông báo cho Tên (bây giờ [1996-97], không dùng nữa) và thuộc tính ID tiêu chuẩn cung cấp cho nó cùng một giá trị mã thông báo.

Họ dễ dàng thuyết phục được đội quân nghiệp dư viết mã ngu dốt trước đó rằng Tên và ID thực tế giống nhau, ngoại trừ thuộc tính ID ngắn hơn và do đó tiết kiệm byte và thuận tiện hơn cho người viết mã so với thuộc tính Tên cổ. Tất nhiên đó là một lời nói dối. Hoặc - trong các bài viết HTML được xuất bản thay thế của họ, các bài viết thuyết phục rằng bạn sẽ cần cung cấp cả Tên và ID cho các thẻ của mình để công cụ Scripting có thể truy cập được.

Những kẻ giết người khảm [tên mã là "Mozilla"] đã rất tức giận, họ nghĩ rằng "nếu chúng ta đi xuống, thì Internet cũng vậy".

Microsoft đang trỗi dậy - mặt khác - ngây thơ đến mức họ nghĩ rằng họ nên giữ lại sự phản đối và bị đánh dấu để xóa thuộc tính Tên và coi nó như một ID là một Định danh duy nhất để họ không phá vỡ chức năng tạo tập lệnh của các trang cũ được mã hóa bởi các học viên Netscape. Họ đã sai lầm chết người ...

Và sự trở lại của một tập hợp các yếu tố xung đột ID cũng không phải là một giải pháp cho vấn đề nhân tạo có chủ ý này. Thật ra nó đã đánh bại toàn bộ mục đích.

Và đây là lý do duy nhất khiến W3C trở nên xấu xí và cho chúng ta những thành ngữ như document.getElementByIdvà cú pháp phiền phức rococo đi kèm của loại ... (...)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.