Nó nguy hiểm như thế nào trong JavaScript, thực sự, để cho rằng undefined không bị ghi đè?


86

Mỗi khi bất kỳ ai đề cập đến thử nghiệm chống lại undefined, nó chỉ ra rằng đó undefinedkhông phải là một từ khóa để nó có thể được đặt thành"hello" , vì vậy bạn nên sử dụng typeof x == "undefined" thay thế. Điều này có vẻ vô lý đối với tôi. Sẽ chẳng có ai làm điều đó cả, và nếu họ làm vậy thì sẽ đủ lý do để không bao giờ sử dụng bất kỳ đoạn mã nào họ đã viết ... đúng không?

Tôi tìm thấy một ví dụ của một ai đó vô tình cài đặt undefinedđể null, và điều này đã được đưa ra như một lý do để tránh giả định rằng undefinedkhông được ghi đè. Nhưng nếu họ làm điều đó, lỗi sẽ không bị phát hiện và tôi không biết làm thế nào tốt hơn.

Trong C ++, mọi người đều biết rằng việc nói đó là hợp pháp #define true false, nhưng không ai khuyên bạn nên tránh truevà sử dụng 0 == 0thay thế. Bạn cứ cho rằng không ai đủ lớn để làm điều đó, và nếu họ làm vậy, đừng bao giờ tin tưởng mã của họ nữa.

Điều này đã bao giờ thực sự cắn ai đó ở nơi người khác được chỉ định undefined(có chủ đích) và nó phá mã của bạn hay đây là một mối đe dọa giả định hơn? Tôi sẵn sàng tận dụng cơ hội của mình để làm cho mã của tôi dễ đọc hơn một chút. Đây có phải là một ý tưởng thực sự tồi?

Để nhắc lại, tôi không yêu cầu làm thế nào để bảo vệ chống lại không xác định được chỉ định lại. Tôi đã thấy những thủ thuật đó được viết 100 lần rồi. Tôi đang hỏi rằng nó nguy hiểm như thế nào nếu không sử dụng những thủ thuật đó.


7
Tôi sẽ rất vui, nhưng tôi không cảm thấy có vẻ như bất kỳ câu trả lời nào trong ba câu trả lời được đưa ra thực hiện tốt việc trả lời câu hỏi. Tôi đã cố gắng nói rõ rằng tôi không yêu cầu chia sẻ lại các câu trả lời mà tôi đã liên kết, nhưng đó vẫn là những gì tôi nhận được. Nếu gauche không chấp nhận câu trả lời ngay cả khi đó không phải là điều tôi đang hỏi, hãy cho tôi biết và tôi sẽ tiếp tục và chấp nhận câu trả lời!
Cosmologicon

1
Tuy nhiên, tôi nghĩ rằng tất cả các sự kiện đều được trình bày ở đây. Vì vậy, những gì bạn đang nói là bạn muốn một câu trả lời hoặc ý kiến ​​chủ quan, điều này chỉ dẫn đến bất đồng. Đó là lý do cụm từ "phương pháp hay nhất" không được phép sử dụng trong tiêu đề câu hỏi. Bạn là người duy nhất có thể biết mức độ nguy hiểm trong kịch bản của bạn. Và nếu bạn đang viết một thư viện phổ biến nơi bạn không kiểm soát tất cả các 'biến', thì hàm wrapper (không xác định) {} dường như là một câu trả lời tuyệt vời. Tại sao không sử dụng nó và chấp nhận câu trả lời đó?
shannon

4
Nếu ai đó lo lắng về việc ai đó xác định lại undefined, bạn nên lo lắng nhiều hơn về việc ai đó xác định lại XMLHttpRequest, hoặc alert. Tất cả các chức năng chúng tôi sử dụng từ đó windowcó thể đã được định nghĩa lại. Và nếu bạn chỉ lo lắng về việc một đồng nghiệp vô tình làm điều đó, tại sao lại tin tưởng họ không làm window.addEventListener = "coolbeans"? Câu trả lời là không phải lo lắng về bất kỳ điều gì trong số đó. Nếu ai đó đang đưa JS vào trang của bạn một cách ác ý thì bạn vẫn bị truy đuổi. Làm việc để ngăn chặn điều đó xảy ra ngay từ đầu.
Chris Middleton

Câu trả lời:


56

Không, tôi không bao giờ có. Điều này chủ yếu là do tôi phát triển trên các trình duyệt hiện đại, hầu hết đều tuân thủ ECMAScript 5. Tiêu chuẩn ES5 ra lệnh undefinedhiện chỉ đọc. Nếu bạn sử dụng chế độ nghiêm ngặt (bạn nên làm như vậy), một lỗi sẽ xuất hiện nếu bạn vô tình cố gắng sửa đổi nó.

undefined = 5;
alert(undefined); // still undefined
'use strict';
undefined = 5; // throws TypeError

Những gì bạn không nên làm là tạo phạm vi của riêng bạn, có thể thay đổi undefined:

(function (undefined) {
    // don't do this, because now `undefined` can be changed
    undefined = 5;
})();

Không đổi là tốt. Vẫn không cần thiết, nhưng tốt.

(function () {
    const undefined = void 0;
})();

Câu lệnh đầu tiên của bạn chỉ đảm bảo rằng bạn không vô tình ghi đè không xác định trong khi phát triển, nó vẫn gây ra mối đe dọa tương tự khi chạy với mã khác trên máy tính khách.
bennedich

1
@bennedich: Tôi biết, tôi đã nói rằng tôi chưa bao giờ gặp phải vấn đề đó, nhưng đây là những gì bạn nên làm .
Ry-

1
@bennedich Bạn không có khả năng tình cờ ghi đè lên bất kỳ biến nào khác phải không?
Ates Goral

40

Không có mã thích hợp sẽ làm một điều như vậy. Nhưng bạn không bao giờ có thể biết một số nhà phát triển thông minh hoặc một plugin / thư viện / tập lệnh bạn đang sử dụng đã làm gì. Mặt khác, điều đó cực kỳ khó xảy ra và các trình duyệt hiện đại sẽ không cho phép ghi đè lên undefined, vì vậy nếu bạn đang sử dụng một trình duyệt như vậy để phát triển, bạn sẽ nhanh chóng nhận ra nếu có bất kỳ mã nào cố gắng ghi đè lên nó.


Và mặc dù bạn không yêu cầu điều đó - nhiều người có thể sẽ tìm thấy câu hỏi này khi tìm kiếm undefinedvấn đề phổ biến hơn "cách bảo vệ chống lại xác định lại ", vì vậy tôi sẽ trả lời rằng:

Có một cách rất tốt để có được một trình duyệt thực sự không xác định cho undefined dù trình duyệt cũ đến đâu:

(function(undefined) {
    // your code where undefined is undefined
})();

Điều này hoạt động vì một đối số không được chỉ định luôn luôn là undefined. Bạn cũng có thể làm điều đó với một hàm chấp nhận một số đối số thực, ví dụ như thế này khi bạn đang sử dụng jQuery. Thông thường, bạn nên đảm bảo một môi trường lành mạnh theo cách này:

(function($, window, undefined) {
    // your code where undefined is undefined
})(jQuery, this);

Sau đó, bạn có thể chắc chắn rằng bên trong hàm ẩn danh đó, những điều sau là đúng:

  • $ === jQuery
  • window === [the global object]
  • undefined === [undefined].

Tuy nhiên, lưu ý rằng đôi khi typeof x === 'undefined'thực sự cần thiết: Nếu biến xchưa bao giờ được đặt thành giá trị (trái với được đặt thành undefined), việc đọc xtheo một cách khác chẳng hạn như if(x === undefined)sẽ gây ra lỗi. Tuy nhiên, điều này không áp dụng cho các thuộc tính đối tượng, vì vậy nếu bạn biết rằng đó yluôn là một đối tượng thì if(y.x === undefined)sẽ hoàn toàn an toàn.


2
Tuyên bố của bạn về việc xkhông được đặt thành giá trị không hoàn toàn đúng (xem jsfiddle.net/MgADz ); nó đúng hơn nếu nó thực sự không được định nghĩa (xem jsfiddle.net/MgADz/1 ).
Ry-

7
Một lần nữa, nếu ai đó vô tình nói undefined = someVariablerằng đó là một lỗi và bạn muốn mọi thứ bị hỏng . Ít nhất là tôi làm.
Cosmologicon

2
Tôi đã làm việc với một cơ sở mã có tập lệnh kế thừa được rút gọn ghi đè lên không xác định, chúng tôi không có thời gian hoặc ngân sách để viết lại tập lệnh, đây là một ví dụ mà typeof x == "undefined" được yêu cầu, điều này không lạ và có lẽ một thói quen tốt.
Damen TheSifter

2
Tôi quan tâm đến lý do tại sao tất cả các ví dụ sử dụng "không xác định" làm đối số bổ sung trong hàm? Nhưng có thể có tình huống nếu ai đó vượt qua một tham số bổ sung (được xác định) do lỗi và tất cả logic sẽ không thành công. Tại sao không sử dụng một cái gì đó như function () {var _undef; if (someVal == _undef) {làm gì đó}};
Oleksandr_DJ

4
@Oleksandr_DJ Chính xác. Tạo nên một giá trị mà bạn biếtundefinedvà assign mà để undefinedtrong phạm vi. Đừng bỏ undefinedngỏ để ghi đè nếu bạn chuyển vào đối số "quá nhiều". Điều đó dẫn đến lỗi, và là một mô hình vốn dĩ không phòng thủ, đặc biệt là khi, như Lucero chỉ ra , có những lựa chọn thay thế rất dễ dàng để có được các undefinedgiá trị vững chắc trong phạm vi.
ruffin

19

Có một giải pháp đơn giản cho điều đó: so sánh với void 0cái nào luôn không xác định.

Lưu ý rằng bạn nên tránh ==vì nó có thể ép buộc các giá trị. Sử dụng ===(và !==) thay thế.

Điều đó nói rằng, biến không xác định có thể được đặt do lỗi nếu ai đó viết =thay vì ==khi so sánh một cái gì đó với undefined.


IMO, đây là câu trả lời tốt nhất.
abhisekp

1
Hãy xem xét rằng điều đó foo === void 0có thể không được đọc mượt mà foo === undefinedvà bất biến đó undefinedđược hỗ trợ đầy đủ bởi các trình duyệt hiện đại (IE 9+) như bạn có thể thấy trong bảng tương thích này .
Daniel AR Werner

3

Chỉ có bạn mới biết mã bạn sử dụng và do đó nó nguy hiểm như thế nào. Câu hỏi này không thể được trả lời theo cách bạn đã làm rõ mà bạn muốn nó được trả lời.

1) Tạo chính sách nhóm, không cho phép xác định lại không xác định, dành nó để sử dụng phổ biến hơn. Quét mã hiện có của bạn cho nhiệm vụ còn lại không xác định.

2) Nếu bạn không kiểm soát tất cả các tình huống, nếu mã của bạn được sử dụng bên ngoài các tình huống mà bạn hoặc chính sách của bạn kiểm soát, thì rõ ràng câu trả lời của bạn là khác. Quét mã sử dụng tập lệnh của bạn. Rất tiếc, hãy quét web để tìm số liệu thống kê về bài tập còn lại chưa xác định nếu bạn muốn, nhưng tôi nghi ngờ điều đó đã được thực hiện cho bạn, bởi vì thay vào đó, bạn chỉ cần theo đuổi câu trả lời số 1 hoặc số 3 ở đây sẽ dễ dàng hơn.

3) Và nếu câu trả lời đó không đủ tốt, có thể là do, một lần nữa, bạn yêu cầu một câu trả lời khác. Có thể bạn đang viết một thư viện phổ biến sẽ được sử dụng bên trong tường lửa của công ty và bạn không có quyền truy cập vào mã gọi. Sau đó, sử dụng một trong những câu trả lời hay khác ở đây. Lưu ý rằng thư viện jQuery phổ biến thực hành đóng gói âm thanh và bắt đầu:

(function( window, undefined ) {

Chỉ bạn mới có thể trả lời câu hỏi của mình theo cách cụ thể mà bạn tìm kiếm. Còn gì nữa để nói?

chỉnh sửa: ps nếu bạn thực sự muốn ý kiến ​​của tôi, tôi sẽ nói với bạn rằng nó không nguy hiểm chút nào. Bất cứ điều gì có khả năng gây ra lỗi (chẳng hạn như gán cho không xác định, rõ ràng là một hành vi rủi ro được ghi chép đầy đủ) đều là một khiếm khuyết. Đó là khiếm khuyết là rủi ro. Nhưng đó chỉ là trong các tình huống của tôi, nơi tôi có thể đủ khả năng để giữ quan điểm đó. Như tôi khuyên bạn nên làm, tôi đã trả lời câu hỏi cho các trường hợp sử dụng của mình.


3

Nó an toàn để kiểm tra chống lại không xác định. Như bạn đã đề cập. Nếu bạn nhận được một số mã ghi đè lên nó (rất có thể ứng biến), chỉ cần không sử dụng nó nữa.

Có thể nếu bạn đang tạo một thư viện để sử dụng chung, bạn có thể sử dụng một số kỹ thuật để tránh người dùng thay đổi nó. Nhưng ngay cả trong trường hợp này, đó là vấn đề của họ, không phải thư viện của bạn.


2

Bạn có thể sử dụng undefinedmã của mình khi viết mã cho các trình duyệt hỗ trợ ECMAScript 5.1 vì nó là bất biến theo đặc điểm ngôn ngữ .

Cũng thấy này bảng tính tương thích hoặc này caniuse ECMAScript 5 để thấy rằng tất cả các trình duyệt hiện đại (IE 9+) đã thực hiện bất biếnundefined .


1

Nó không nguy hiểm chút nào. Nó chỉ có thể được ghi đè khi chạy trên công cụ ES3 và nó sẽ không còn được sử dụng nữa.


0

Trước hết, nếu mã của bạn bị hỏng có lẽ không phải do một số nhà phát triển khác ngoài kia "đang cố gắng trở thành một kẻ xấu" như bạn nói.

Đó undefinedkhông phải là một từ khóa. Nhưng nó một nguyên thủy cấp độ toàn cầu. Nó được dự định sử dụng như thế này (xem "không xác định" tại developer.mozilla.org ):

var x;
if (x === undefined) {
    // these statements execute
}
else {
    // these statements do not execute
}

Cách thay thế phổ biến cho điều đó (cũng từ MDN ) và theo tôi cách tốt hơn là:

// x has not been declared before
if (typeof x === 'undefined') { // evaluates to true without errors
    // these statements execute
}

if(x === undefined){ // throws a ReferenceError

}

Điều này có một vài ưu điểm, điều hiển nhiên (từ các bình luận) là nó không kích hoạt ngoại lệ khi x không được khai báo. Cũng cần lưu ý rằng MDN cũng chỉ ra rằng điều quan trọng là phải sử dụng ===over ==trong trường hợp đầu tiên vì:

var x=null;
if (x === undefined) {
    // this is probably what you meant to do
    // these lines will not execute in this case
}
else if (x == undefined) {
    // these statements will execute even though x *is* defined (as null)
}
else {
    // these statements do not execute
}

Đây là một lý do khác thường bị bỏ qua tại sao có lẽ tốt hơn là chỉ sử dụng giải pháp thay thế thứ hai trong mọi trường hợp.

Kết luận: Không sai khi viết mã theo cách đầu tiên và chắc chắn là không nguy hiểm. Đối số bạn đã thấy mà bạn sử dụng làm ví dụ chống lại nó (rằng nó có thể bị ghi đè) không phải là đối số mạnh nhất để viết mã thay thế bằng typeof. Nhưng việc sử dụng typeofmạnh hơn vì một lý do cụ thể: nó không ném ra ngoại lệ khi var của bạn không được khai báo. Nó cũng có thể được lập luận rằng sử dụng ==thay vì ===là một sai lầm phổ biến trong trường hợp nó không làm những gì bạn mong đợi. Vậy tại sao không sử dụng typeof?


1
"Cái nào có một vài ưu điểm, điều rõ ràng là nó không kích hoạt ngoại lệ khi x không được khai báo." Hãy để tôi nói thẳng. Bạn nghĩ rằng đó là một lợi thế khi im lặng bỏ qua ngoại lệ xảy ra khi bạn sử dụng một biến không được khai báo? Điều đó dường như rất dễ xảy ra lỗi. Bạn có thể giải thích lý do tại sao bạn nghĩ đó không phải là một bất lợi khủng khiếp?
Cosmologicon
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.