JavaScript'teki instanceof operatörü nedir?


313

instanceofJavaScript anahtar kelime ilk karşılaşıldığında insanların JavaScript nesne yönelimli bir programlama dili değildir düşünüyorsanız eğilimindedir oldukça kafa karıştırıcı olabilir.

  • Bu ne?
  • Hangi sorunları çözüyor?
  • Ne zaman uygun ve ne zaman uygun değil?

3
Aşağıdaki cevaplar çok faydalı olsa da, gerçek kelime uygulamalarında çok fazla kullanmıyorsunuz (en azından kullanmıyorum). Bir dize tutan ve üzerinde kontrol eden bir object.type özelliği yapmak.
Omar Al-Ithawi

4
JS hiçbir anlam ifade etmiyor: "foo" instanceof String=> false, 1 instanceof Number=> false, {} instanceof Object=> false. Ne dedin?!
morbusg

12
@morbusg yorumunuz yanıltıcı. Birincisi "foo" instanceof String => falsedoğrudur, çünkü typeof "foo" == 'string'. new String("foo") instanceof String => true, çünkü typeof String == 'function'- işlevi sınıf gibi ele almalısınız (sınıfın tanımı). Değişken olarak atadığınızda instanceofbazı function(sınıf) olur var v = new AnythingWhatTypeofEqualsFunction(). Aynı şey için de geçerlidir 1. typeof 1 == 'number'- 'numara' 'işlevi' değil :) Sonraki - {} instanceof Objectolan TRUEdüğüm ve modern tarayıcılarda
FIDER

1
@fider: Bu bir rubyistten gelen dil spekülasyonuna yönelik bir yorumdu.
morbusg

@morbusg - ({}) instanceof Objectgeri dönecektir true. Aslında yazdığınız kod size bir hata verecektir.
DDM

Yanıtlar:


279

örneği

Sol Taraf (LHS) işleneni, bir sınıfın gerçek oluşturucusu olan Sağ Taraf (RHS) işlenmesinde test edilen gerçek nesnedir. Temel tanım:

Checks the current object and returns true if the object
is of the specified object type.

İşte bazı iyi örnekler ve doğrudan Mozilla'nın geliştirici sitesinden alınan bir örnek :

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

Bahsetmeye değer bir şey instanceof, nesne sınıfın prototipinden miras alırsa doğru olarak değerlendirilir:

var p = new Person("Jon");
p instanceof Person

Bu mirastan p instanceof Personberi doğrudur .pPerson.prototype

OP'nin talebi üzerine

Bazı örnek kod ve bir açıklama ile küçük bir örnek ekledim.

Bir değişkeni bildirdiğinizde değişkene belirli bir tür verirsiniz.

Örneğin:

int i;
float f;
Customer c;

Yukarıda bazı değişkenler göstermek, yani i, fve c. Türleri integer, floatve bir kullanıcı tanımlı Customerveri türü. Yukarıdaki gibi türler yalnızca JavaScript için değil, herhangi bir dil için olabilir. Bununla birlikte, bir değişkeni açıkça tanımladığınız bir değişkeni bildirdiğinizde var x, x bir sayı / dize / kullanıcı tanımlı veri türü olabilir. Öyleyse instanceof, nesneyi, yukarıdan Customeryapabileceğimiz nesneyi alarak yukarıda belirtilen türde olup olmadığını kontrol etmek için ne yapar :

var c = new Customer();
c instanceof Customer; //Returns true as c is just a customer
c instanceof String; //Returns false as c is not a string, it's a customer silly!

Yukarıda bunun tiple cbeyan edildiğini gördük Customer. Bunu yeniledik ve türünün olup olmadığını kontrol ettik Customer. Tabii ki, doğru döner. Sonra hala Customernesneyi kullanarak bir String. Hayır, kesinlikle bir Stringbiz bir Customernesneyi değil, bir Stringnesneyi yendik . Bu durumda, false değerini döndürür.

Gerçekten bu kadar basit!


@Alon - Sana bir örnek ekledim. Yukarıya bakın, color1 tür dizgidir, bu nedenle color1 instanceof String;renk1 bir dize olduğu için bunun doğru döneceğini söylediğinizde .
JonH

@Alon - Ne tür bir nesne olduğunu görmek için bir nesneyi kontrol eder. Bir kişi / müşteri nesnesi düşünün. Yani person p = new person()p artık bir dize türü değil, bir kişi türüdür.
JonH

JavaScript'te, bir değişkenin ömrü boyunca farklı bir türe sahip olma esnekliğine sahip olduğunu anlamak zor olabilir. Kod örneği: jsfiddle.net/sikusikucom/znSPv
Moey

@ Siku-Siku.Com - İlkelden ilkel bir konuya herhangi bir sorun olmadan var zero = 0; alert(zero); zero = "0"; alert(zero)gittik . intstring
JonH

Oh, çok çetrefilli / yeniye anlamına geliyordu anlama (değil do ) JavaScript "esneklik", başkasıyla söyledi. örneğin bir değişken türünü değiştirmek için açık döküm gerektiren bir dile alışmış olanlar için. Sizin de belirttiğiniz gibi, bu ilkel örneğin dan türünü değiştirmek çok kolaydır intilkel için string.
moey

95

Anında, şu ana kadar yorumların hiçbirinde ele alınmamış gibi görünen önemli bir yön vardır: kalıtım. İnstanceof kullanılarak değerlendirilen bir değişken, prototip kalıtım nedeniyle birden çok "tip" için true değerini döndürebilir.

Örneğin, bir tür ve bir alt tür tanımlayalım:

function Foo(){ //a Foo constructor
    //assign some props
    return this;
}

function SubFoo(){ //a SubFoo constructor
    Foo.call( this ); //inherit static props
    //assign some new props
    return this;
}

SubFoo.prototype = Object.create(Foo.prototype); // Inherit prototype
SubFoo.prototype.constructor = SubFoo;

Şimdi birkaç "sınıfımız" var, bazı örnekler yapalım ve bunların ne olduğunu öğrenelim:

var 
    foo = new Foo()
,   subfoo = new SubFoo()
;

alert( 
    "Q: Is foo an instance of Foo? "
+   "A: " + ( foo instanceof Foo ) 
); // -> true

alert( 
    "Q: Is foo an instance of SubFoo? " 
+   "A: " + ( foo instanceof SubFoo ) 
); // -> false

alert( 
    "Q: Is subfoo an instance of Foo? "
+   "A: " + ( subfoo instanceof Foo ) 
); // -> true

alert( 
    "Q: Is subfoo an instance of SubFoo? "
+   "A: " + ( subfoo instanceof SubFoo ) 
); // -> true

alert( 
    "Q: Is subfoo an instance of Object? "
+   "A: " + ( subfoo instanceof Object ) 
); // -> true

Son satırı görüyor musun? Bir işleve yapılan tüm "yeni" çağrılar, Object'ten devralınan bir nesneyi döndürür. Bu, nesne oluşturma stilini kullanırken bile geçerlidir:

alert( 
    "Q: Is {} an instance of Object? "
+   "A: " + ( {} instanceof Object ) 
); // -> true

Peki ya “sınıf” tanımlarının kendileri? Bunlar neyi temsil ediyor?

alert( 
    "Q: Is Foo an instance of Object? "
+   "A:" + ( Foo instanceof Object) 
); // -> true

alert( 
    "Q: Is Foo an instance of Function? "
+   "A:" + ( Foo instanceof Function) 
); // -> true

Herhangi bir nesnenin MULTIPLE türlerinin bir örneği olabileceğini anlamanın önemli olduğunu düşünüyorum, çünkü siz (yanlış), diyelim ve nesne ile bir işlevi kullanarak ayırt edebileceğinizi varsayıyorsunuz instanceof. Bu son örnek olarak, açık bir şekilde bir işlev gösterir olan bir nesne.

Bu, herhangi bir miras modeli kullanıyorsanız ve bir nesnenin dölünü ördek yazma dışındaki yöntemlerle onaylamak istiyorsanız da önemlidir.

Umarım bu kimsenin keşfetmesine yardımcı olur instanceof.


Daha da müthiş olan, prototipten miras aldıktan sonra SubFoo.prototype = new Foo();ona daha fazla yöntem ekleyebileceğiniz ve subfoo instanceof Fooçekin yine de geçeceğisubfoo instanceof SubFoo
Cory Danielson

87

Buradaki diğer cevaplar doğrudur, ancak instanceofgerçekte nasıl çalıştığına girmezler, bu da bazı dil avukatlarının ilgisini çekebilir.

JavaScript'teki her nesnenin __proto__özellik üzerinden erişilebilen bir prototipi vardır . İşlevler ayrıca, kendileri tarafından oluşturulan nesneler prototypeiçin ilk olan bir özelliğe sahiptir __proto__. Bir işlev oluşturulduğunda kendisine benzersiz bir nesne verilir prototype. instanceofOperatör bir cevap vermek için bu eşsizliği kullanır. instanceofBir işlev olarak yazdıysanız, neye benzeyebileceği aşağıda açıklanmıştır .

function instance_of(V, F) {
  var O = F.prototype;
  V = V.__proto__;
  while (true) {
    if (V === null)
      return false;
    if (O === V)
      return true;
    V = V.__proto__;
  }
}

Bu temel olarak ECMA-262 sürüm 5.1 (ES5 olarak da bilinir), bölüm 15.3.5.3'ü açıklamaktadır.

Herhangi bir nesneyi bir işlevin prototypeözelliğine yeniden atayabileceğinizi ve bir nesnenin __proto__özelliğini oluşturulduktan sonra yeniden atayabileceğinizi unutmayın . Bu size bazı ilginç sonuçlar verecektir:

function F() { }
function G() { }
var p = {};
F.prototype = p;
G.prototype = p;
var f = new F();
var g = new G();

f instanceof F;   // returns true
f instanceof G;   // returns true
g instanceof F;   // returns true
g instanceof G;   // returns true

F.prototype = {};
f instanceof F;   // returns false
g.__proto__ = {};
g instanceof G;   // returns false

5
__proto__IE'de " " özelliğinin doğrudan değiştirilmesine izin verilmediğini belirtmek gerekir. Doğru hatırlıyorsam, mülkün doğrudan manipülasyonu ECMA spesifikasyonuna dahil değildir, bu nedenle akademik arayışlar dışında atama için kullanmak muhtemelen kötü bir fikirdir.
webnesto

@ webnesto, bu doğru, proto teknik özelliklerde değil. IE olsa da desteklemediğini bilmiyordum. Doğrudan manipülasyon derken, JS koduna hiç maruz kalmadı mı yoksa Yazılabilir değil mi demek istediniz?
Jay Conrod

2
Eski sürümlerde% 100 emin değilim. Buradan geliyor gibi görünüyor ( stackoverflow.com/questions/8413505/proto-for-ie9-or-ie10 ) IE9'da en azından okunabilir (değiştirilebilir değil). Ayrıca tarayıcıların tamamen bırakıyor gibi göründüğü de dikkat çekicidir.
webnesto

4
Proto özelliğinin örtülü varlığını anlamak, kullanıcı kodu tarafından erişilebilir olsa da olmasa da önemlidir. +10 Eğer şartnameye atıfta bulunabilseydim, tam olarak buraya aradığım şey buydu.
Mike Edwards

3
Prototip bağlantısını elde etmek için kullanın Object.getPrototypeOf(o), bu __proto__sizin tarif ettiğinizle aynı olacaktır , ancak ECMAScript'e uygundur.
froginvasion

45

Ben instanceof nesneyi bildirirken "yeni" anahtar kelime kullanımı ile tanımlanmış olduğunu belirtmek gerekir. JonH örneğinde;

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

Bahsetmediği şey şudur;

var color1 = String("green");
color1 instanceof String; // returns false

"New" belirtilmesi, String yapıcı işlevinin son durumunu yalnızca return değerine ayarlamak yerine color1 var'a kopyaladı. Bu yeni anahtar kelimenin ne yaptığını daha iyi gösterdiğini düşünüyorum;

function Test(name){
    this.test = function(){
        return 'This will only work through the "new" keyword.';
    }
    return name;
}

var test = new Test('test');
test.test(); // returns 'This will only work through the "new" keyword.'
test // returns the instance object of the Test() function.

var test = Test('test');
test.test(); // throws TypeError: Object #<Test> has no method 'test'
test // returns 'test'

"New" kullanılması, işlev içindeki "this" değerini bildirilen var değerine atar, bunun yerine kullanmazsa dönüş değerini atar.


2
newJavaScript'in herhangi bir türüyle kullanmak mantıklı değil , bu da kabul edilen cevabı yeni başlayanlar için çok daha kafa karıştırıcı hale getiriyor. text = String('test')ve options = {}test vermeyeceğiz instanceofile oldukça ama typeofbunun yerine.
Ryan

3
Date.getTime () // başarısız. evet, yeni önemlidir.
Stephen Belanger

1
Bunu bir konsolda çalıştırmayı deneyin. GetTime () mevcut olmadığından bir hata alırsınız. Yeni kullanmanız gerekiyor.
Stephen Belanger

8

Ve hata işleme ve hata ayıklama için kullanabilirsiniz, örneğin:

try{
    somefunction();
} 
catch(error){
    if (error instanceof TypeError) {
        // Handle type Error
    } else if (error instanceof ReferenceError) {
        // Handle ReferenceError
    } else {
        // Handle all other error types
    }
}

3
//Vehicle is a function. But by naming conventions
//(first letter is uppercase), it is also an object
//constructor function ("class").
function Vehicle(numWheels) {
    this.numWheels = numWheels;
}

//We can create new instances and check their types.
myRoadster = new Vehicle(4);
alert(myRoadster instanceof Vehicle);

3

Bu ne?

Javascript prototip bir dildir, yani 'kalıtım' için prototipler kullanır. instanceofBir yapıcı işlevinin varsa operatör test prototypepropertype mevcut olan __proto__bir nesnenin zinciri. Bu, aşağıdakilerin yapılacağı anlamına gelir (testObj'nin bir işlev nesnesi olduğu varsayılarak):

obj instanceof testObj;
  1. Nesnenin prototipinin yapıcı prototipine eşit olup olmadığını kontrol edin: obj.__proto__ === testObj.prototype >> true instanceofdöndürülecekse true.
  2. Prototip zincirine tırmanacak. Örneğin: obj.__proto__.__proto__ === testObj.prototype >> bu ise true instanceofgeri döner true.
  3. Nesnenin tam prototipi incelenene kadar 2. adımı tekrarlar. Hiçbir nesnenin prototip zincirinde ile eşleşti ise testObj.prototypeo zaman instanceofoperatör dönecektir false.

Misal:

function Person(name) {
  this.name = name;
}
var me = new Person('Willem');

console.log(me instanceof Person); // true
// because:  me.__proto__ === Person.prototype  // evaluates true

console.log(me instanceof Object); // true
// because:  me.__proto__.__proto__ === Object.prototype  // evaluates true

console.log(me instanceof Array);  // false
// because: Array is nowhere on the prototype chain

Hangi sorunları çözüyor?

Bir nesnenin belirli bir prototipten türetilmiş olup olmadığını rahatça kontrol etme problemini çözdü. Örneğin, bir işlev çeşitli prototiplere sahip olabilen bir nesneyi aldığında. Ardından, prototip zincirindeki yöntemleri kullanmadan önce instanceof, bu yöntemlerin nesne üzerinde olup olmadığını kontrol etmek için operatörü kullanabiliriz .

Misal:

function Person1 (name) {
  this.name = name;
}

function Person2 (name) {
  this.name = name;
}

Person1.prototype.talkP1 = function () {
  console.log('Person 1 talking');
}

Person2.prototype.talkP2 = function () {
  console.log('Person 2 talking');
}


function talk (person) {
  if (person instanceof Person1) {
    person.talkP1();
  }
  
  if (person instanceof Person2) {
    person.talkP2();
  }
  
  
}

const pers1 = new Person1 ('p1');
const pers2 = new Person2 ('p2');

talk(pers1);
talk(pers2);

Burada talk()ilk olarak prototipin nesnede bulunup bulunmadığı kontrol edilir. Bundan sonra yürütmek için uygun yöntem seçilir. Bu kontrolün yapılmaması, mevcut olmayan bir yöntemin yürütülmesine ve dolayısıyla bir referans hatasına neden olabilir.

Ne zaman uygun ve ne zaman uygun değil?

Biz zaten bunu aştık. Bir nesneyle bir şey yapmadan önce prototipinin kontrol edilmesi gerektiğinde kullanın.


1
Sana "Başka şeyler yazmak istedim düşünüyorum bir yapıcı fonksiyonunun prototipi bir yapıcı prototipi özelliğinde bir yerde ortaya "
Bergi

Kişilerin bir arabirimi paylaşmasının ve bu yöntemlerin her ikisini de adlandırmasının daha uygun olacağını belirtmek isteyebilirsiniz PersonX.prototype.talk, böylece talkişlev basitçe yapabilir person.talk().
Bergi

Tamamen doğru güncellediniz, bu yüzden tanım daha iyi. İşaret ettiğiniz için teşekkürler!
Willem van der Veen

Ayrıca, __proto__dokümantasyonda kullanmayın , kullanımdan kaldırıldı - Object.getPrototype()bunun yerine yazın
Bergi

1

"Ne zaman uygun ve ne zaman uygun değil?" Sorusunda 2 sentim:

instanceofüretim kodunda nadiren yararlıdır, ancak kodunuzun doğru türdeki nesneleri döndürdüğünü / oluşturduğunu iddia etmek istediğiniz testlerde kullanışlıdır. Kodunuzun döndürdüğü / oluşturduğu nesne türleri konusunda açık olursanız, testleriniz kodunuzu anlamak ve belgelemek için bir araç olarak daha güçlü hale gelir.


1

instanceofsadece sözdizimsel şekerdir isPrototypeOf:

function Ctor() {}
var o = new Ctor();

o instanceof Ctor; // true
Ctor.prototype.isPrototypeOf(o); // true

o instanceof Ctor === Ctor.prototype.isPrototypeOf(o); // equivalent

instanceof sadece bir nesnenin kurucusunun prototipine bağlıdır.

Yapıcı sadece normal bir işlevdir. Her şey Javascript'teki bir nesne olduğu için, kesinlikle bir işlev nesnesidir. Ve bu fonksiyon nesnesinin bir prototipi vardır, çünkü her fonksiyonun bir prototipi vardır.

Bir prototip yalnızca başka bir nesnenin prototip zincirinde bulunan normal bir nesnedir. Bu, başka bir nesnenin prototip zincirinde olmak, bir prototipin nesnesini yaptığı anlamına gelir:

function f() {} //  ordinary function
var o = {}, // ordinary object
 p;

f.prototype = o; // oops, o is a prototype now
p = new f(); // oops, f is a constructor now

o.isPrototypeOf(p); // true
p instanceof f; // true

instanceofO JavaScript var olmayan sınıfları, sahte çünkü operatör kaçınılmalıdır. classES2015'te olmayan anahtar kelimeye rağmen class, yine sadece sözdizimsel şeker olduğu için ... ama bu başka bir hikaye.


1
İlk satır yanlış! Daha fazla bilgi için buraya bakın : "isPrototypeOf () örneği işleç örneğinden farklıdır." AFunction nesnesinin örneği "nesnesinde, nesne prototip zinciri AFunction'a karşı değil AFunction.prototype ile denetlenir."
Yan Foto

1
@Yan Ve hala instanceoftüretilmiştir isPrototypeOf. Buna sözdizimsel şeker diyorum. Ve MDN kaynağınız bir şaka değil mi?

Hayır. Şaka değil ve olması gerekiyordu, ama yine de yanlış bağlantı. Ben gerekiyordu bu bir yayınlanmıştır. Ben technicalities girmek istemiyorum, ama instanceof değil aynı şeyi yapmak isPrototypeOf. Bu kadar.
Yan Foto

0

Ben sadece gerçek bir dünya uygulaması buldum ve şimdi daha sık kullanacağını düşünüyorum.

JQuery olayları kullanıyorsanız, bazen doğrudan (olaysız) da çağrılabilecek daha genel bir işlev yazmak istersiniz. Sen kullanabilirsiniz instanceofsenin fonksiyonun ilk parametresi bir örneği olup olmadığını kontrol etmek jQuery.Eventve uygun tepki verir.

var myFunction = function (el) {                
    if (el instanceof $.Event) 
        // event specific code
    else
        // generic code
};

$('button').click(recalc);    // Will execute event specific code
recalc('myParameter');  // Will execute generic code

Benim durumumda, fonksiyonun bir şey hesaplaması gerekiyordu (bir düğmedeki click olayı ile) veya sadece belirli bir eleman. Kullandığım kod:

var recalc = function (el) { 
    el = (el == undefined || el instanceof $.Event) ? $('span.allItems') : $(el);
    // calculate...
};
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.