biến === không xác định so với biến typeof ===


300

Các lõi Phong cách viết jQuery đề nghị hai cách khác nhau để kiểm tra xem một biến được định nghĩa.

  • Biến toàn cầu: typeof variable === "undefined"
  • Biến cục bộ: variable === undefined
  • Tính chất: object.prop === undefined

Tại sao jQuery sử dụng một cách tiếp cận cho các biến toàn cục và một cách khác cho các thuộc tính và thuộc tính?


Tôi không thể trả lời câu hỏi tại sao JQuery sẽ sử dụng cả hai cách tiếp cận, nhưng Javascript có một số điểm thú vị có nghĩa là hai điều này khác nhau một cách tinh tế. Nó không phải là vấn đề hầu hết thời gian (ví dụ nếu mã của bạn lành mạnh), tuy nhiên vẫn có sự khác biệt: Xem tại đây để viết bài - wtfjs.com/2010/02/15/undposed-is-mutable
Spudley

2
Như @Struppi đã chỉ ra, hàm ngoài cùng của jQuery có một đối số có tên là không xác định. Trong jQuery, foo === undefinedđang kiểm tra bản sao cục bộ của không xác định thay vì toàn cục (window.und xác định), có thể đã được sửa đổi bằng mã điên. Thực tế là không xác định được là có thể thay đổi chắc chắn đáng chú ý và tôi rất vui vì bạn đã làm. (+1)
Patrick McElhaney

1
Liên kết hiện tại cho bài viết đó là wtfjs.com/wtfs/2010-02-15-undDef-is-mutable
enigment 31/03/18

Câu trả lời:


366

Đối với các biến không được khai báo, typeof foosẽ trả về chuỗi ký tự "undefined", trong khi kiểm tra danh tính foo === undefinedsẽ gây ra lỗi "foo không được xác định" .

Đối với các biến cục bộ (mà bạn biết được khai báo ở đâu đó), sẽ không xảy ra lỗi như vậy, do đó kiểm tra danh tính.


3
@goreSplatter Bạn không thể xóa nó ngay bây giờ. :-) Thật khó để lựa chọn, nhưng cách đặt câu hỏi, câu trả lời này phù hợp hơn. Bất cứ ai quan tâm đến cách thức hoạt động không xác định nói chung (như tôi) cũng nên xem các câu trả lời khác, đặc biệt là của @ Tim.
Patrick McElhaney

4
Tôi sẽ thêm dấu ngoặc kép ( typeof foo; // -> "undefined") để nhấn mạnh nó là một chuỗi chứ không phải giá trị nguyên thủy undefined.
c24w

117

Tôi muốn sử dụng typeof foo === "undefined"ở mọi nơi. Điều đó không bao giờ có thể đi sai.

Tôi tưởng tượng lý do tại sao jQuery khuyến nghị hai phương thức khác nhau là vì chúng xác định undefinedbiến riêng của chúng trong hàm mà mã jQuery sống, do đó, trong hàm đó undefinedan toàn không bị giả mạo từ bên ngoài. Tôi cũng sẽ tưởng tượng rằng ai đó ở đâu đó đã điểm chuẩn hai cách tiếp cận khác nhau và phát hiện ra rằng foo === undefinednhanh hơn và do đó quyết định đó là cách để đi. [CẬP NHẬT: như đã lưu ý trong các bình luận, so sánh với undefinedcũng ngắn hơn một chút, có thể là một sự cân nhắc.] Tuy nhiên, mức tăng trong các tình huống thực tế sẽ hoàn toàn không đáng kể: kiểm tra này sẽ không bao giờ là bất kỳ loại tắc nghẽn nào, và những gì bạn mất rất đáng kể: việc đánh giá một thuộc tính của đối tượng máy chủ để so sánh có thể gây ra lỗi trong khitypeof kiểm tra sẽ không bao giờ

Ví dụ: phần sau được sử dụng trong IE để phân tích cú pháp XML:

var x = new ActiveXObject("Microsoft.XMLDOM");

Để kiểm tra xem nó có loadXMLphương pháp nào an toàn không:

typeof x.loadXML === "undefined"; // Returns false

Mặt khác:

x.loadXML === undefined; // Throws an error

CẬP NHẬT

Một ưu điểm khác của typeofséc mà tôi quên đề cập đến là nó cũng hoạt động với các biến không được khai báo, mà foo === undefinedséc không có, và trên thực tế đã ném a ReferenceError. Cảm ơn @LinusKleen đã nhắc nhở tôi. Ví dụ:

typeof someUndeclaredVariable; // "undefined"
someUndeclaredVariable === undefined; // throws a ReferenceError

Dòng dưới cùng: luôn luôn sử dụng typeofkiểm tra.


10
Cảm ơn Tim. Quan điểm của bạn về hiệu suất có ý nghĩa. Nhóm jQuery có thể quan tâm nhiều hơn về tác động đến kích thước tệp. foo === undefined, khi được giảm thiểu, có lẽ là một cái gì đó giống như f===u, trong khi typeof foo === "undefined"chỉ có thể được giảm xuống typeof f==="undefined".
Patrick McElhaney

1
Bạn có thể định nghĩa var u = "undefined"và giảm nó xuống typeof f==u, giúp cải thiện mọi thứ nhưng vẫn lớn hơn.
Tim Down

5
Điểm tốt, nhưng tôi không chắc chắn sự an toàn của việc typeofchống lại các biến không được khai báo là một lợi thế. Nếu bất cứ điều gì nó cho phép lỗi chính tả trôi qua dễ dàng hơn và tôi không thể thấy khi nào bạn thực sự muốn kiểm tra loại biến không được khai báo.
David Tang

2
@ Box9: Tôi có thể tưởng tượng sử dụng nó trong thư viện để kiểm tra sự hiện diện của thư viện khác.
Tim Down

2
@jontro: Đó là một lý do để không sử dụng JSLint.
Tim Down

29

Một lý do khác để sử dụng biến thể typeof: undefinedcó thể được xác định lại.

undefined = "foo";
var variable = "foo";
if (variable === undefined)
  console.log("eh, what?!");

Kết quả là typeof variable không thể.

Cập nhật : lưu ý rằng đây không phải là trường hợp trong ES5, toàn cầu undefinedlà một thuộc tính không thể cấu hình, không thể ghi:

15.1.1 Thuộc tính giá trị của đối tượng toàn cầu
[...]
15.1.1.3 không xác định
Giá trị của undefinedkhông xác định (xem 8.1). Thuộc tính này có các thuộc tính
{[[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false}.

Nhưng nó vẫn có thể bị che khuất bởi một biến cục bộ:

(function() {
  var undefined = "foo";
  var variable = "foo";
  if (variable === undefined)
    console.log("eh, what?!");  
})()

hoặc tham số:

(function(undefined) {
  var variable = "foo";
  if (variable === undefined)
    console.log("eh, what?!");  
})("foo")

17
Không thể được xác định lại trong ES5.
Ry-

6
undefinedThuộc tính toàn cầu không thể được xác định lại trong ES5, nhưng vẫn có thể bị che khuất bằng một biến cục bộ. void 0ngắn hơn và an toàn hơn.
Oriol

7

Bởi vì undefinedkhông phải lúc nào cũng được khai báo, nhưng jQuery khai báo undefinedtrong hàm chính của nó. Vì vậy, họ sử dụng undefinedgiá trị an toàn trong nội bộ, nhưng bên ngoài, họ sử dụng typeofphong cách để được an toàn.



1

Đối với các biến cục bộ, kiểm tra với localVar === undefinedsẽ hoạt động vì chúng phải được xác định ở đâu đó trong phạm vi cục bộ hoặc chúng sẽ không được coi là cục bộ.

Đối với các biến không cục bộ và không được xác định ở bất kỳ đâu, kiểm tra someVar === undefinedsẽ đưa ra ngoại lệ: Uncaught ReferenceError: j không được xác định

Đây là một số mã sẽ làm rõ những gì tôi đang nói ở trên. Hãy chú ý đến ý kiến ​​nội tuyến để rõ ràng hơn .

function f (x) {
    if (x === undefined) console.log('x is undefined [x === undefined].');
    else console.log('x is not undefined [x === undefined.]');

    if (typeof(x) === 'undefined') console.log('x is undefined [typeof(x) === \'undefined\'].');
    else console.log('x is not undefined [typeof(x) === \'undefined\'].');

    // This will throw exception because what the hell is j? It is nowhere to be found.
    try
    {
        if (j === undefined) console.log('j is undefined [j === undefined].');
        else console.log('j is not undefined [j === undefined].');
    }
    catch(e){console.log('Error!!! Cannot use [j === undefined] because j is nowhere to be found in our source code.');}

    // However this will not throw exception
    if (typeof j === 'undefined') console.log('j is undefined (typeof(x) === \'undefined\'). We can use this check even though j is nowhere to be found in our source code and it will not throw.');
    else console.log('j is not undefined [typeof(x) === \'undefined\'].');
};

Nếu chúng ta gọi mã ở trên như thế này:

f();

Đầu ra sẽ là thế này:

x is undefined [x === undefined].
x is undefined [typeof(x) === 'undefined'].
Error!!! Cannot use [j === undefined] because j is nowhere to be found in our source code.
j is undefined (typeof(x) === 'undefined'). We can use this check even though j is nowhere to be found in our source code and it will not throw.

Nếu chúng ta gọi mã ở trên như thế này (với bất kỳ giá trị nào thực sự):

f(null); 
f(1);

Đầu ra sẽ là:

x is not undefined [x === undefined].
x is not undefined [typeof(x) === 'undefined'].
Error!!! Cannot use [j === undefined] because j is nowhere to be found in our source code.
j is undefined (typeof(x) === 'undefined'). We can use this check even though j is nowhere to be found in our source code and it will not throw.

Khi bạn thực hiện kiểm tra như thế này: typeof x === 'undefined'về cơ bản, bạn đang hỏi điều này: Vui lòng kiểm tra xem biến xcó tồn tại (đã được xác định) ở đâu đó trong mã nguồn không. (nhiều hơn hoặc ít hơn). Nếu bạn biết C # hoặc Java, loại kiểm tra này không bao giờ được thực hiện bởi vì nếu nó không tồn tại, nó sẽ không biên dịch.

<== Fiddle tôi ==>


1

Tóm lược:

Khi ở phạm vi toàn cầu, chúng tôi thực sự muốn trả về true nếu biến không được khai báo hoặc có giá trị undefined:

var globalVar1;

// This variable is declared, but not defined and thus has the value undefined
console.log(globalVar1 === undefined);

// This variable is not declared and thus will throw a referenceError
console.log(globalVar2 === undefined);

Bởi vì trong phạm vi toàn cầu, chúng tôi không chắc chắn 100% nếu một biến được khai báo, điều này có thể cung cấp cho chúng tôi tham chiếuError. Khi chúng ta sử dụng typeoftoán tử trên biến không xác định, chúng ta sẽ không gặp vấn đề này khi biến không được khai báo:

var globalVar1;

console.log(typeof globalVar1 === 'undefined');
console.log(typeof globalVar2 === 'undefined');

Điều này là do thực tế là typeoftoán tử trả về chuỗi undefinedkhi một biến không được khai báo hoặc hiện đang giữ giá trị undefinedchính xác như những gì chúng ta muốn.


  • Với các biến cục bộ, chúng tôi không gặp phải vấn đề này bởi vì chúng tôi biết trước rằng biến này sẽ tồn tại. Chúng ta có thể chỉ cần nhìn vào hàm tương ứng nếu có biến.
  • Với các thuộc tính đối tượng, chúng ta không gặp phải vấn đề này bởi vì khi chúng ta cố gắng tra cứu một thuộc tính đối tượng không tồn tại, chúng ta cũng nhận được giá trị undefined

var obj = {};

console.log(obj.myProp === undefined);


-5

typeof a === 'undefined'nhanh hơn a === 'undefined'khoảng 2 lần trên nút v6.9.1.


3
Đó không phải là những thứ mà bạn đã gõ. Tôi nghĩ bạn có nghĩa là undefinedở phần thứ hai, không phải'undefined'
đáng sợ
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.