Tại sao instanceof trả về false cho một số chữ?


284
"foo" instanceof String //=> false
"foo" instanceof Object //=> false
true instanceof Boolean //=> false
true instanceof Object //=> false
false instanceof Boolean //=> false
false instanceof Object //=> false

// the tests against Object really don't make sense

Mảng chữ và đối tượng chữ phù hợp ...

[0,1] instanceof Array //=> true
{0:1} instanceof Object //=> true

Tại sao không phải tất cả trong số họ? Hoặc, tại sao tất cả họ không không ?
Và, họ là một ví dụ của, sau đó là gì?

Nó giống nhau trong FF3, IE7, Opera và Chrome. Vì vậy, ít nhất là nó phù hợp.


Bỏ lỡ một vài.

12.21 instanceof Number //=> false
/foo/ instanceof RegExp //=> true

Câu trả lời:


424

Nguyên thủy là một loại khác với các đối tượng được tạo từ trong Javascript. Từ các tài liệu API Mozilla :

var color1 = new String("green");
color1 instanceof String; // returns true
var color2 = "coral";
color2 instanceof String; // returns false (color2 is not a String object)

Tôi không thể tìm thấy bất kỳ cách nào để xây dựng các kiểu nguyên thủy bằng mã, có lẽ điều đó là không thể. Đây có lẽ là lý do tại sao mọi người sử dụng typeof "foo" === "string"thay vì instanceof.

Một cách dễ dàng để ghi nhớ những điều như thế này là tự hỏi mình "Tôi tự hỏi điều gì sẽ lành mạnh và dễ học"? Dù câu trả lời là gì, Javascript vẫn làm điều khác.


5
Mỗi ngày với một lý do mới để ghét JavaScript là một ngày tốt. Tôi biết nó đã quá hạn lâu nhưng tôi cảm ơn bạn vì bài đăng này.
toniedzwiedz

57
Thuật ngữ của bạn là sai. Từ "nghĩa đen" dùng để chỉ một cú pháp tạo dữ liệu mà không cần sử dụng hàm tạo. Nó không đề cập đến dữ liệu kết quả. Cú pháp bằng chữ có thể được sử dụng để tạo cả đối tượng và không đối tượng. Thuật ngữ chính xác là "nguyên thủy", dùng để chỉ dữ liệu phi đối tượng. Một số dữ liệu có cả biểu diễn nguyên thủy và đối tượng. Chuỗi là một trong những loại dữ liệu.
trạng thái màu xám sẽ đến vào

14
FYI, bạn có thể tạo nguyên thủy mà không cần cú pháp theo nghĩa đen. (new String()).valueOf();
trạng thái màu xám sẽ đến vào

11
Lưu ý typeof foo === 'string'là không đủ: xem câu trả lời của axkibe.
Bryan Larsen

1
Ngoài ra, typeof new String('')trả lại"object"
transang

105

Tôi sử dụng:

function isString(s) {
    return typeof(s) === 'string' || s instanceof String;
}

Bởi vì trong chuỗi JavaScript có thể là chữ hoặc đối tượng.


28
Tôi tìm thấy một cái gì đó ngắn gọn btw. function isString(s) { return s.constructor === String; }Hoạt động cho các đối tượng bằng chữ và chuỗi (ít nhất là trong V8)
axkibe

7
Phải yêu JavaScript.
Derek 朕 會

2
Tôi sử dụng jQuery.type (s) === 'string' ( api.jquery.com/jquery.type ), jQuery.isArray (), jQuery.isFunction (), jQuery.isNumeric () khi có thể.
Ivan Samygin

1
@axkibe trong khi bạn đúng, nó gần như không biểu diễn như typeof.
Qix - MONICA ĐƯỢC PHÂN PHỐI

Bạn có thể sử dụng typeof "?" == String.name.toLowerCase () [nhưng tại sao là [] instanceof Array?]
QuentinUK

62

Trong JavaScript, mọi thứ đều là một đối tượng (hoặc ít nhất có thể được coi là một đối tượng), ngoại trừ các nguyên hàm (booleans, null, số, chuỗi và giá trị undefined(và ký hiệu trong ES6)):

console.log(typeof true);           // boolean
console.log(typeof 0);              // number
console.log(typeof "");             // string
console.log(typeof undefined);      // undefined
console.log(typeof null);           // object
console.log(typeof []);             // object
console.log(typeof {});             // object
console.log(typeof function () {}); // function

Như bạn có thể thấy các đối tượng, mảng và giá trị nullđều là các đối tượng được xem xét ( nulllà một tham chiếu đến một đối tượng không tồn tại). Các chức năng được phân biệt bởi vì chúng là một loại đối tượng có thể gọi được đặc biệt . Tuy nhiên họ vẫn là đối tượng.

Mặt khác các literals true, 0, ""undefinedkhông phải là đối tượng. Chúng là các giá trị nguyên thủy trong JavaScript. Tuy nhiên dữ liệu boolean, số và chuỗi cũng có nhà thầu Boolean, NumberStringtương ứng mà quấn nguyên thủy của mình để cung cấp tính năng bổ sung:

console.log(typeof new Boolean(true)); // object
console.log(typeof new Number(0));     // object
console.log(typeof new String(""));    // object

Như bạn có thể nhìn thấy khi giá trị nguyên thủy được gói trong Boolean, NumberStringnhà xây dựng tương ứng họ trở thành đối tượng. Các instanceofnhà điều hành chỉ hoạt động cho các đối tượng (đó là lý do nó sẽ trả về falsecho các giá trị nguyên thủy):

console.log(true instanceof Boolean);              // false
console.log(0 instanceof Number);                  // false
console.log("" instanceof String);                 // false
console.log(new Boolean(true) instanceof Boolean); // true
console.log(new Number(0) instanceof Number);      // true
console.log(new String("") instanceof String);     // true

Như bạn có thể thấy cả hai typeofinstanceofkhông đủ để kiểm tra xem một giá trị là boolean, một số hay một chuỗi - typeofchỉ hoạt động cho các booleans, số và chuỗi nguyên thủy; và instanceofkhông hoạt động cho booleans nguyên thủy, số và chuỗi.

May mắn thay, có một giải pháp đơn giản cho vấn đề này. Việc triển khai mặc định toString(nghĩa là được xác định rõ ràng trên Object.prototype.toString) trả về thuộc tính bên trong [[Class]]của cả các giá trị và đối tượng nguyên thủy:

function classOf(value) {
    return Object.prototype.toString.call(value);
}

console.log(classOf(true));              // [object Boolean]
console.log(classOf(0));                 // [object Number]
console.log(classOf(""));                // [object String]
console.log(classOf(new Boolean(true))); // [object Boolean]
console.log(classOf(new Number(0)));     // [object Number]
console.log(classOf(new String("")));    // [object String]

[[Class]]Thuộc tính bên trong của một giá trị hữu ích hơn nhiều so với typeofgiá trị. Chúng ta có thể sử dụng Object.prototype.toStringđể tạo phiên bản typeoftoán tử (hữu ích hơn) của riêng mình như sau:

function typeOf(value) {
    return Object.prototype.toString.call(value).slice(8, -1);
}

console.log(typeOf(true));              // Boolean
console.log(typeOf(0));                 // Number
console.log(typeOf(""));                // String
console.log(typeOf(new Boolean(true))); // Boolean
console.log(typeOf(new Number(0)));     // Number
console.log(typeOf(new String("")));    // String

Hy vọng bài viết này đã giúp. Để biết thêm về sự khác biệt giữa các đối tượng nguyên thủy và các đối tượng được bọc, hãy đọc bài đăng trên blog sau: Cuộc sống bí mật của người nguyên thủy JavaScript


6
+1, altough nullcũng là một giá trị nguyên thủy (chỉ người typeofvận hành khó hiểu)
Bergi

33

Bạn có thể sử dụng thuộc tính constructor:

'foo'.constructor == String // returns true
true.constructor == Boolean // returns true

18
Lưu ý rằng khi kiểm tra các biến kỹ thuật này có thể thất bại trong một số trường hợp nhất định. Có một tham chiếu ngầm để cửa sổ hiện trước StringBooleantrong ví dụ trên, vì vậy nếu bạn đang thử nghiệm các constructortài sản của một biến chuỗi được tạo ra trong một cửa sổ khác (như một popup hoặc khung) nó sẽ không được tính bằng đơn giản String, nó sẽ bằng thatOtherWindowsName.String.
Michael Mathews

Và không thể đối phó với điều này và trả về kết quả boolean thích hợp?
Chris Noe

5
điều này không thành công nếu bạn đã thông qua một hậu duệ của Chuỗi.
Bryan Larsen

1
@MichaelMathews: Điều này có tác dụng khắc phục rằng:Object.prototype.toString.call('foo') === '[object String]'
rvighne

@BryanLarsen và @MichaelMathews Có vấn đề gì trong việc sử dụng d.constructor == Stringkhông? Ví dụ với một toán tử đẳng thức lỏng lẻo.
dotnetCarpenter

7
 typeof(text) === 'string' || text instanceof String; 

bạn có thể sử dụng nó, nó sẽ hoạt động cho cả hai trường hợp như

  1. var text="foo"; // typeof sẽ hoạt động

  2. String text= new String("foo"); // instanceof sẽ hoạt động


3

Điều này được định nghĩa trong đặc tả ECMAScript Phần 7.3.19 Bước 3 :If Type(O) is not Object, return false.

Nói cách khác, nếu Objtrong Obj instanceof Callablekhông phải là một đối tượng, thì instanceofsẽ ngắn mạch falsetrực tiếp.


1

Tôi tin rằng tôi đã đưa ra một giải pháp khả thi:

Object.getPrototypeOf('test') === String.prototype    //true
Object.getPrototypeOf(1) === String.prototype         //false

-1

https://www.npmjs.com/package/typeof

Trả về một chuỗi đại diện của instanceof(tên nhà xây dựng)

function instanceOf(object) {
  var type = typeof object

  if (type === 'undefined') {
    return 'undefined'
  }

  if (object) {
    type = object.constructor.name
  } else if (type === 'object') {
    type = Object.prototype.toString.call(object).slice(8, -1)
  }

  return type.toLowerCase()
}

instanceOf(false)                  // "boolean"
instanceOf(new Promise(() => {}))  // "promise"
instanceOf(null)                   // "null"
instanceOf(undefined)              // "undefined"
instanceOf(1)                      // "number"
instanceOf(() => {})               // "function"
instanceOf([])                     // "array"

-2

Đối với tôi sự nhầm lẫn gây ra bởi

"str".__proto__ // #1
=> String

Vì vậy, "str" istanceof Stringnên trở lại truevì cách istanceof hoạt động như dưới đây:

"str".__proto__ == String.prototype // #2
=> true

Kết quả của biểu thức # 1# 2 mâu thuẫn với nhau, do đó nên có một trong số chúng sai.

# 1 là sai

Tôi nhận ra rằng nó gây ra bởi thuộc tính __proto__không chuẩn, vì vậy hãy sử dụng thuộc tính tiêu chuẩn:Object.getPrototypeOf

Object.getPrototypeOf("str") // #3
=> TypeError: Object.getPrototypeOf called on non-object

Bây giờ không có sự nhầm lẫn giữa biểu thức # 2# 3


2
# 1 là chính xác, nhưng đó là do trình truy cập thuộc tính , hộp chứa giá trị nguyên thủy cho loại đối tượng tương ứng của nó, tương tự Object("str").__proto__hoặc Object("str") instanceof String.
Jonathan Lonowski

@JonathanLonowski cảm ơn vì đã chỉ ra điều này. Tôi không biết điều đó
mko

-8

Hoặc bạn chỉ có thể thực hiện chức năng của riêng mình như vậy:

function isInstanceOf(obj, clazz){
  return (obj instanceof eval("("+clazz+")")) || (typeof obj == clazz.toLowerCase());
};

sử dụng:

isInstanceOf('','String');
isInstanceOf(new String(), 'String');

Những điều này nên trả lại đúng sự thật.


14
Tôi thấy eval. Tà ác.
Aaria Carter-Weir
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.