Mengapa instanceof false untuk beberapa literal?

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

Array literal dan Object literals match ...

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

Kenapa tidak semuanya? Atau, mengapa mereka semua tidak ?
Dan, apa yang mereka contoh?

Sama di FF3, IE7, Opera, dan Chrome. Jadi, setidaknya konsisten.


Kehilangan beberapa.

12.21 instanceof Number //=> false
/foo/ instanceof RegExp //=> true
Jonathan Lonowski
sumber

Jawaban:

424

Primitif adalah jenis yang berbeda dari objek yang dibuat dari dalam Javascript. Dari dokumen Mozilla API :

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

Saya tidak dapat menemukan cara untuk membangun tipe primitif dengan kode, mungkin itu tidak mungkin. Ini mungkin mengapa orang menggunakan typeof "foo" === "string"bukaninstanceof .

Cara mudah untuk mengingat hal-hal seperti ini adalah bertanya pada diri sendiri, "Saya ingin tahu apa yang waras dan mudah dipelajari"? Apa pun jawabannya, Javascript melakukan hal lain.

John Millikin
sumber
5
Setiap hari dengan alasan baru untuk membenci JavaScript adalah hari yang baik. Saya tahu ini sudah lama terlambat tapi saya berterima kasih atas pos ini.
toniedzwiedz
57
Terminologi Anda salah. Kata "literal" mengacu pada sintaks untuk membuat data tanpa menggunakan konstruktor. Itu tidak merujuk pada data yang dihasilkan. Sintaks literal dapat digunakan untuk membuat objek dan non-objek. Istilah yang benar adalah "primitif", yang mengacu pada data non-objek. Beberapa data memiliki representasi primitif dan objek. String adalah salah satu dari tipe data tersebut.
negara abu
14
FYI, Anda dapat membuat primitif tanpa sintaks literal. (new String()).valueOf();
negara abu
11
Catatan itu typeof foo === 'string'tidak cukup: lihat jawaban axkibe.
Bryan Larsen
1
Sebagai tambahan, typeof new String('')pengembalian"object"
transang
105

Saya menggunakan:

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

Karena dalam JavaScript string dapat berupa literal atau objek.

axkibe
sumber
28
Saya menemukan sesuatu yang pendek btw. function isString(s) { return s.constructor === String; }Berfungsi untuk literal dan objek string (setidaknya dalam V8)
axkibe
7
Harus cinta JavaScript.
Derek 朕 會 功夫
2
Saya menggunakan jQuery.type = s 'string' ( api.jquery.com/jquery.type ), jQuery.isArray (), jQuery.isFunction (), jQuery.isNumeric () jika memungkinkan.
Ivan Samygin
1
@axkibe saat Anda benar, itu hampir tidak performant sebagai typeof.
Qix - MONICA DISEBUTKAN
Anda dapat menggunakan jenis "?" == String.name.toLowerCase () [tetapi mengapa [] instance dari Array?]
QuentinUK
62

Dalam JavaScript, segala sesuatu adalah objek (atau setidaknya dapat dianggap sebagai objek), kecuali primitif (boolean, null, angka, string, dan nilainya undefined(dan simbol dalam 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

Seperti yang Anda lihat objek, array dan nilainya nullsemua dianggap objek ( nulladalah referensi ke objek yang tidak ada). Fungsi dibedakan karena mereka adalah tipe khusus objek yang bisa dipanggil . Namun mereka masih obyek.

Di sisi lain literal true, 0, ""dan undefinedtidak objek. Mereka adalah nilai primitif dalam JavaScript. Namun boolean, angka dan string juga memiliki konstruktor Boolean, Numberdan Stringmasing - masing yang membungkus primitif masing-masing untuk memberikan fungsionalitas tambahan:

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

Seperti yang Anda lihat ketika nilai primitif dibungkus di dalam Boolean, Numberdan Stringkonstruktor masing-masing menjadi objek. The instanceofOperator hanya bekerja untuk benda (yang mengapa ia mengembalikan falsenilai-nilai primitif):

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

Seperti yang Anda lihat keduanya typeofdan instanceoftidak cukup untuk menguji apakah suatu nilai adalah boolean, angka atau string - typeofhanya berfungsi untuk boolean primitif, angka dan string; daninstanceof tidak berfungsi untuk boolean primitif, angka, dan string.

Untungnya ada solusi sederhana untuk masalah ini. Implementasi default toString(yaitu seperti yang didefinisikan secara bawaan Object.prototype.toString) mengembalikan [[Class]]properti internal dari kedua nilai primitif dan objek:

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]]Properti internal suatu nilai jauh lebih bermanfaat daripada typeofnilai itu. Kita dapat menggunakan Object.prototype.toStringuntuk membuat versi typeofoperator kami sendiri (lebih bermanfaat) sebagai berikut:

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

Semoga artikel ini membantu. Untuk mengetahui lebih lanjut tentang perbedaan antara primitif dan objek terbungkus, baca posting blog berikut: Kehidupan Rahasia Primitif JavaScript

Aadit M Shah
sumber
6
+1, meskipun nulljuga merupakan nilai primitif (hanya typeofoperator yang membingungkan)
Bergi
33

Anda dapat menggunakan properti konstruktor:

'foo'.constructor == String // returns true
true.constructor == Boolean // returns true
pengguna144049
sumber
18
Perhatikan bahwa ketika menguji variabel teknik ini dapat gagal dalam keadaan tertentu. Ada referensi implisit ke jendela saat ini di depan Stringdan Booleandalam contoh di atas, jadi jika Anda menguji constructorproperti variabel string yang dibuat di jendela lain (seperti popup atau bingkai) itu tidak akan sama dengan sederhana String, itu akan sama dengan thatOtherWindowsName.String.
Michael Mathews
Dan bukankah contoh dari berurusan dengan ini dan mengembalikan hasil boolean yang sesuai?
Chris Noe
5
ini gagal jika Anda melewati keturunan String.
Bryan Larsen
1
@MichaelMathews: Ini berfungsi untuk memperbaiki itu:Object.prototype.toString.call('foo') === '[object String]'
rvighne
@BryanLarsen dan @MichaelMathews Apakah ada masalah dalam menggunakan d.constructor == String? Misalnya dengan operator kesetaraan longgar.
dotnetCarpenter
7
 typeof(text) === 'string' || text instanceof String; 

Anda dapat menggunakan ini, ini akan berfungsi untuk kedua kasus

  1. var text="foo"; // typeof akan bekerja

  2. String text= new String("foo"); // instanceof akan bekerja

saurabhgoyal795
sumber
3

Ini didefinisikan dalam Bagian spesifikasi ECMAScript 7.3.19 Langkah 3 :If Type(O) is not Object, return false.

Dengan kata lain, jika Objin Obj instanceof Callablebukan objek, maka instanceofhubungan arus pendek akan falselangsung.

HKTonyLee
sumber
1

Saya yakin saya telah menemukan solusi yang layak:

Object.getPrototypeOf('test') === String.prototype    //true
Object.getPrototypeOf(1) === String.prototype         //false
Robby Harris
sumber
-1

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

Mengembalikan representasi string dari instanceof(nama konstruktor)

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"
samdd
sumber
-2

Bagi saya kebingungan yang disebabkan oleh

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

Jadi "str" istanceof Stringharus kembali truekarena cara kerja seperti di bawah ini:

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

Hasil dari ekspresi # 1 dan # 2 saling bertentangan, jadi harus ada yang salah.

# 1 salah

Saya mengetahui bahwa itu disebabkan oleh __proto__properti non-standar, jadi gunakan yang standar:Object.getPrototypeOf

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

Sekarang tidak ada kebingungan antara ekspresi # 2 dan # 3

mko
sumber
2
# 1 benar, tetapi itu karena accessor properti , yang mengotakkan nilai primitif ke jenis objek masing-masing, mirip dengan Object("str").__proto__atau Object("str") instanceof String.
Jonathan Lonowski
@JonathanLonowski terima kasih telah menunjukkan ini. Saya tidak tahu itu
mko
-8

Atau Anda bisa membuat fungsi sendiri seperti:

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

pemakaian:

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

Keduanya harus kembali benar.

sth
sumber
14
Saya melihat eval. Jahat.
Aaria Carter-Weir