İnstanceof neden bazı değişmez değerler için yanlış döndürür?


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

Dizi değişmezleri ve Nesne değişmezleri eşleşiyor ...

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

Neden hepsi olmasın? Ya da neden hepsi olmasın ?
Peki, o zaman neye benziyorlar?

FF3, IE7, Opera ve Chrome için de aynı şey geçerli. Yani, en azından tutarlı.


Birkaç cevapsız.

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

Yanıtlar:


424

Temel öğeler, Javascript içinden oluşturulan nesnelerden farklı türde bir türdür. Gönderen Mozilla API docs :

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

Kod ile ilkel türleri oluşturmak için herhangi bir yol bulamıyorum, belki de mümkün değildir. Muhtemelen insanlar typeof "foo" === "string"bunun yerine kullanıyor instanceof.

Bunun gibi şeyleri hatırlamanın kolay bir yolu kendinize "Aklı başında ve öğrenmesi kolay ne olacağını merak ediyorum" diye sormak mı? Cevap ne olursa olsun, Javascript başka bir şey yapar.


5
Her gün JavaScript'ten nefret etmek için yeni bir sebeple iyi bir gün. Gecikmiş olduğunu biliyorum ama bu yazı için teşekkür ederim.
toniedzwiedz

57
Terminolojiniz yanlış. "Değişmez" sözcüğü, bir yapıcı kullanmadan veri oluşturmak için bir sözdizimini ifade eder. Ortaya çıkan verilere değinmez. Değişmez sözdizimi, hem nesneleri hem de nesne olmayanları oluşturmak için kullanılabilir. Doğru terim, nesne olmayan verilere atıfta bulunan "ilkeller" dir. Bazı verilerin hem ilkel hem de nesne gösterimleri vardır. Dize, bu veri türlerinden biridir.
gri devlet

14
Bilginize, gerçek sözdizimi olmadan ilkel öğeler oluşturabilirsiniz. (new String()).valueOf();
gri devlet

11
Bunun typeof foo === 'string'yeterli olmadığını unutmayın : axkibe'nin cevabına bakınız.
Bryan Larsen

1
Ek olarak, typeof new String('')iade"object"
transang

105

Kullanırım:

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

Çünkü JavaScript'te dizeler değişmezler veya nesneler olabilir.


28
Btw kısa bir şey buldum. function isString(s) { return s.constructor === String; }
Değişmez

7
JavaScript'i sevmeliyim.
Derek 朕 會 功夫

2
Mümkün olduğunda jQuery.type (s) === 'string' ( api.jquery.com/jquery.type ), jQuery.isArray (), jQuery.isFunction (), jQuery.isNumeric () kullanıyorum.
Ivan Samygin

1
@axkibe haklısın, neredeyse performans kadar değil typeof.
Qix - MONICA

"?" Türünü kullanabilirsiniz. == String.name.toLowerCase () [ama neden [] Array örneğidir?]
QuentinUK

62

JavaScript'te ilkelundefined öğeler (booleans, null, sayı, dize ve değer (ve ES6'daki sembol)) dışında her şey bir nesnedir (veya en azından bir nesne olarak ele alınabilir):

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

Gördüğünüz gibi, diziler ve değerlerin nulltümü nesneler olarak kabul edilir ( nullvar olmayan bir nesneye referanstır). İşlevler ayırt edilebilir, çünkü bunlar özel olarak çağrılabilir nesnelerdir. Ancak hala nesnelerdir.

Değişmezleri Öte yandan true, 0,"" ve undefineddeğil nesneleri vardır. Bunlar JavaScript'teki ilkel değerlerdir. Ancak boolean, sayı ve dizeleri de kurucuya sahip Boolean, Numberve Stringek işlevsellik sağlamak amacıyla kendi temelögeye sarmak hangi sırasıyla:

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

İlkel değerlerin ne zaman sarıldığını görebileceğiniz gibi Boolean,Number ve Stringkurucular sırasıyla onlar nesneler haline gelir. instanceofOperatörü yalnızca (döndürür neden olan nesneler için çalışır falseilkel değerler için):

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

Her ikisini de görebileceğiniz typeofve instanceofbir değerin bir boolean, sayı veya dize olup olmadığını test etmek için yetersiz - typeofyalnızca ilkel boole, sayı ve dize için çalışır; ve instanceofilkel boolelar, sayılar ve karakter dizileri için çalışmaz.

Neyse ki bu sorunun basit bir çözümü var. Varsayılan uygulaması toString(yani yerel olarak tanımlandığı gibi)Object.prototype.toString ) [[Class]], hem ilkel değerlerin hem de nesnelerin dahili özelliğini döndürür :

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]]Bir değerin iç özelliği, değerden çok daha kullanışlıdır typeof. KullanabilirizObject.prototype.toStringtypeofOperatörün kendi (daha kullanışlı) versiyonumuzu aşağıdaki gibi oluşturmak için :

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

Umarım bu makale yardımcı olmuştur. İlkel öğeler ve sarılmış nesneler arasındaki farklar hakkında daha fazla bilgi için aşağıdaki blog gönderisini okuyun: JavaScript İlkellerinin Gizli Yaşamı


6
+1, nullher ne kadar ilkel bir değer olsa da (sadece typeofoperatör kafa karıştırıcıdır)
Bergi

33

Constructor özelliğini kullanabilirsiniz:

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

18
Değişkenleri test ederken bu tekniğin belirli durumlarda başarısız olabileceğini unutmayın. Önünde geçerli pencereye örtük bir referansı var Stringve Booleanyukarıdaki örnekte test ettiğiniz eğer öyleyse, constructor(bir halk ya çerçeve gibi) başka bir pencerede oluşturulan bir dize değişkeni özelliğini de olacak değil sadece eşit olacak String, bu olacak eşit olmak thatOtherWindowsName.String.
Michael Mathews

Ve bununla başa çıkmak ve uygun boole sonucunu döndürmüyor mu?
Chris Noe

5
String'in soyundan geçtiyseniz bu başarısız olur.
Bryan Larsen

1
@MichaelMathews: Bu bunu düzeltmek için çalışır:Object.prototype.toString.call('foo') === '[object String]'
rvighne

@BryanLarsen ve @MichaelMathews Kullanımda herhangi bir sorun var mı d.constructor == String? Örneğin, gevşek bir eşitlik operatörü ile.
16:21

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

Bunu kullanabilirsiniz, her iki durum için de çalışacaktır.

  1. var text="foo"; // typeof çalışacak

  2. String text= new String("foo"); // instanceof çalışacak


3

Bu, ECMAScript spesifikasyonu Bölüm 7.3.19 Adım 3'te tanımlanmıştır. :If Type(O) is not Object, return false.

Başka bir deyişle , Objin Obj instanceof Callablebir nesne değilse, doğrudan instanceofdevreye kısa devre yapar false.


1

Uygun bir çözüm bulduğuma inanıyorum:

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

-1

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

instanceof(Yapıcı adı) dizesinin temsilini döndürür

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

Benim için karışıklık

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

Öyleyse "str" istanceof Stringdönmeliyiz trueçünkü istanceof nasıl çalışır?

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

1 ve 2 numaralı ifadelerin sonuçları birbiriyle çelişmektedir, bu yüzden bunlardan biri yanlış olmalıdır.

# 1 yanlış

Ben neden __proto__standart dışı özelliği olduğunu anlamak , bu yüzden standart bir kullanın:Object.getPrototypeOf

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

Şimdi # 2 ve # 3 ifadeleri arasında karışıklık yok


2
# 1 doğrudur, ancak ilkel değeri veya benzeri nesne türüne göre kutlayan özellik erişimcisinden kaynaklanır . Object("str").__proto__Object("str") instanceof String
Jonathan Lonowski

@JonathanLonowski bunu işaret ettiğiniz için teşekkürler. Bunu bilmiyordum
mko

-8

Ya da sadece kendi işlevinizi şu şekilde yapabilirsiniz:

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

kullanımı:

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

Bunların ikisi de doğru dönmelidir.


14
Eval görüyorum. Kötülük.
Aaria Carter-Weir
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.