2011-12-20 43 views
15

Ai đó có thể giải thích những điều sau đây không?Instanceof không nhất quán

[] instanceof Array; // true 
'' instanceof String; // false 
+1

Ngoài ra 'typeof" "' là '" chuỗi "' và 'typeof []' là '" đối tượng "' (bạn mong muốn '" mảng "' nhưng không sao tôi có thể sống với điều đó) – Halcyon

+0

Đoán, có thể '' là một nguyên thủy, nhưng [] một đối tượng? –

+2

+1 Thú vị, vì '" ".constructor === Chuỗi'. – pimvdb

Trả lời

14

Lưu ý những điều sau:

"" instanceof String;    // => false 
new String("") instanceof String; // => true 

instanceof đòi hỏi một đối tượng, nhưng "" là một chuỗi chữ, và không phải là một đối tượng String. Lưu ý các loại sau đây bằng cách sử dụng chức năng typeof:

typeof ""    // => "string" 
typeof new String("") // => "object" 
typeof []    // => "object" 
typeof new Array() // => "object" 
+0

Vậy thì sự khác nhau giữa một đối tượng 'stringal' và' String' là gì và tại sao nó (rõ ràng) lại quan trọng? Theo như tôi biết chúng có thể được sử dụng thay thế cho nhau nhưng kết quả là bạn không thể sử dụng 'instanceof' để kiểm tra xem cái gì đó là 'chuỗi' – Halcyon

+1

Nhưng không phải là' [] 'một mảng theo cùng một cách mà' '' 'là một chuỗi chữ? – FishBasketGordo

+0

@FishBasketGordo mảng có thể chứa tất cả các loại nguyên thủy và các đối tượng. –

11

Đó là vì '' là nguyên thủy, không phải là một đối tượng.

Một số nguyên thủy trong JavaScript có thể có trình bao bọc đối tượng. Chúng được tạo khi bạn tạo một ví dụ của trình bao bọc bằng cách sử dụng hàm tạo dựng sẵn có new.

Thường cần thiết new vì thường lần hàm sẽ kết hợp với nguyên thủy nếu bạn loại trừ new.

typeof new String(''); // "object" 
typeof String('');  // "string" 
typeof '';    // "string" 

Các nguyên thủy có wrappers Object là string, numberboolean.

Các nguyên thủy không phải là nullundefined.

+0

Vì vậy, nguyên thủy (tức là không bao bọc đối tượng) của '[]' là gì? – Randomblue

+2

Randomblue: Không có. Một mảng luôn là một đối tượng. –

+0

@Randomblue không tồn tại. Tại sao sẽ có một nguyên thủy? – Raynos

3

'' không phải là một ví dụ về bất kỳ điều gì; đó là một kiểu nguyên thủy và nó hoạt động theo cách tương tự như 5.5 hoặc true. Có một sự khác biệt giữa một chuỗi nguyên thủy và một đối tượng String. Xem:

new String('') instanceof String; // true 

Bất cứ điều gì tạo ra với new String(), new Number() hoặc new Boolean() là một wrapper đối tượng xung quanh kiểu nguyên thủy, và chúng không giống nhau.

Để kiểm tra các chuỗi, vv sử dụng typeof thay vì:

typeof '' === 'string'; // true 

Để kiểm tra các cả, sử dụng này:

Object.prototype.toString.call('') === '[object String]'; // true 
Object.prototype.toString.call(new String('')) === '[object String]'; // true 

Có một vài lý do để sử dụng Object.prototype.toString.call cho mã sử dụng chung, cho mảng, chuỗi, số booleans. Chúng là:

  1. Đối với chuỗi, số và booleans, mọi người có thể vượt qua trường hợp của đối tượng bao bọc thay vì các kiểu nguyên thủy. Chúng thường hoạt động theo cùng một cách (với một ẩn số valueOf()) và vì vậy bạn nên chấp nhận chúng nếu viết mã thư viện.
  2. Đối với mảng, nếu bạn nhận được mảng từ cửa sổ khác (nói từ số) thì sử dụng instanceof Array sẽ trả lại false. Phương thức Object.prototype.toString.call hoạt động cho mọi mục đích.

Đây là những gì jQuery và các thư viện lớn, phổ biến khác làm.

1

Tôi đã thực hiện một số thao tác và tôi cho rằng nó phải làm với string interning là tối ưu hóa trình biên dịch.

OK, sẵn sàng cho một số gotchas? : D

"abc" == "abc"; // true 
"abc" === "abc"; // true 

Tôi cho rằng điều này là đúng vì "chuỗi interning" mà tình cờ cũng làm cho rất nhiều ý nghĩa, khái niệm (yay để nhận 'chuỗi' bên phải).

new String("abc") == new String("abc"); // false 
new String("abc") === new String("abc"); // false 

Điều này có ý nghĩa nếu bạn giả định String là đối tượng và đối tượng chỉ bằng chính nó và không bằng đối tượng có trạng thái nội bộ tương tự. Giống như trong Java (hoặc làm thế nào nó được sử dụng để được anyway).

Và bây giờ cho kicker:

(new String("abc")).substr(0,3) === (new String("abc")).substr(0,3); // true! 

Vì vậy, rõ ràng là người phiên dịch JavaScript sẽ luôn thích chuỗi interning qua việc sử dụng các đối tượng String.

Sau đó, tôi phải hỏi, việc sử dụng đối tượng String là gì? Rõ ràng nó không chơi tốt với bạn bè của nó.

+0

Cái đầu tiên, "abc" === "abc" ', không phải vì chuỗi ký tự. Tính bình đẳng nghiêm ngặt hoạt động như bạn mong đợi đối với các kiểu nguyên thủy. '===' chỉ là "tham chiếu-bằng" đối với các đối tượng. – Ryan

+0

Chuỗi 'loại' chỉ có ở đó để cho phép bạn mở rộng nguyên mẫu của nó và cũng cho phép bạn tạo các chuỗi giống như' Objects'. Đó là các đối tượng (tương tự như con trỏ trong C) sẽ chỉ là '===' nếu chúng là 'cùng một con trỏ' – Adaptabi

Các vấn đề liên quan