Czym jest operator instanceof w JavaScript?

Słowo kluczowe instanceof w JavaScript może być dość mylące, gdy jest napotkane po raz pierwszy, ponieważ ludzie mają tendencję do myślenia, że JavaScript nie jest obiektowym językiem programowania.

    Co to jest?
  • Jakie problemy rozwiązuje?
  • Kiedy jest to właściwe, a kiedy nie?
Author: Alon Gubkin, 2010-03-15

10 answers

Instanceof

Operand lewej strony (LHS) jest rzeczywistym obiektem testowanym do operandu prawej strony (RHS), który jest faktycznym konstruktorem klasy. Podstawowa definicja brzmi:

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

Oto kilka dobrych przykładów i oto przykład zaczerpnięty bezpośrednio z witryny programistycznej Mozilli:

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)

Warto wspomnieć, że instanceof ewaluuje na true, jeśli obiekt dziedziczy z prototypu classe:

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

Że is {[6] } is true since p inherits from Person.prototype.

Na żądanie OP

Dodałem mały przykład z przykładowym kodem i wyjaśnieniem.

Kiedy deklarujesz zmienną, nadajesz jej określony typ.

Na przykład:

int i;
float f;
Customer c;

Powyższe pokazuje kilka zmiennych, a mianowicie i, f, i c. Do rodzaju należą następujące gatunki integer, float oraz zdefiniowany przez Użytkownika typ danych Customer. Typy takie jak powyższe mogą dotyczyć dowolnego języka, a nie tylko JavaScript. Jednak w JavaScript, gdy deklarujesz zmienną, nie definiujesz jawnie typu var x, x może być typem danych zdefiniowanym przez użytkownika. To, co instanceof robi, to sprawdza obiekt, aby sprawdzić, czy jest on typu określonego tak od góry biorąc Customer obiekt możemy zrobić:

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!

Powyżej widzieliśmy, że c został zadeklarowany z typem Customer. Zmieniliśmy go i sprawdziliśmy, czy jest typu Customer, czy nie. Oczywiście, że tak. Następnie używając obiektu Customer możemy sprawdź, czy jest to String. Nie, na pewno nie String dodaliśmy Customer obiekt, a nie String obiekt. W tym przypadku zwraca false.

To naprawdę takie proste!
 243
Author: JonH,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-22 10:58:51

Jest ważny aspekt instanceof, który nie wydaje się być omówiony w żadnym z komentarzy do tej pory: dziedziczenie. Zmienna oceniana za pomocą instanceof może zwrócić true dla wielu "typów" ze względu na dziedziczenie prototypowe.

Na przykład zdefiniujmy typ i podtyp:

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 = new Foo(); // Inherit prototype

Teraz, gdy mamy kilka "klas", zróbmy kilka instancji i dowiedzmy się, czego są instancjami:

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
Widzisz ostatnią linijkę? Wszystkie" nowe " wywołania funkcji zwraca obiekt, który dziedziczy po obiekcie. Jest to prawdą nawet przy użyciu skrótu tworzenia obiektów:
alert( 
    "Q: Is {} an instance of Object? "
+   "A: " + ( {} instanceof Object ) 
); // -> true

A co z samymi definicjami "klasy"? Jakie są ich przykłady?

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

Uważam, że zrozumienie, że każdy obiekt może być instancją wielu typów jest ważne, ponieważ ty mój (niepoprawnie) zakładasz, że możesz odróżnić, powiedzmy i obiekt i funkcję za pomocą instanceof. Jak ten ostatni przykład wyraźnie pokazuje funkcja jest an obiekt.

Jest to również ważne, jeśli używasz dowolnych wzorców dziedziczenia i chcesz potwierdzić potomstwo obiektu za pomocą metod innych niż pisanie kaczką.

Mam nadzieję, że to pomoże każdemu odkrywać instanceof.

 87
Author: webnesto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-30 16:09:26

Inne odpowiedzi tutaj są poprawne, ale nie wnikają w to, jak naprawdę działa, co może być interesujące dla niektórych prawników językowych.

Każdy obiekt w JavaScript posiada prototyp, dostępny za pośrednictwem właściwości __proto__. Funkcje mają również właściwość prototype, która jest początkową __proto__ dla dowolnych obiektów przez nie utworzonych. Gdy funkcja jest tworzona, otrzymuje unikalny obiekt dla prototype. Operator instanceof używa tej wyjątkowości, aby udzielić odpowiedzi. Oto co instanceof może wyglądać, gdybyś napisał to jako funkcję.

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__;
  }
}

Jest to w zasadzie parafrazowanie ECMA-262 edition 5.1 (znany również jako ES5), sekcja 15.3.5.3.

Zauważ, że możesz przypisać dowolny obiekt do właściwości prototype funkcji i możesz przypisać obiekt __proto__ po jej zbudowaniu. To da ci kilka ciekawych wyników:

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
 85
Author: Jay Conrod,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-09 23:04:33

Myślę, że warto zauważyć, że instanceof jest definiowany przez użycie słowa kluczowego" new " podczas deklarowania obiektu. W przykładzie z JonH;

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

Nie wspomniał o tym;

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

Podanie "new" faktycznie skopiowało stan końcowy konstruktora Łańcuchowego funkcji do var color1, a nie tylko ustawiło go na wartość zwracaną. Myślę, że to lepiej pokazuje, co robi nowe słowo kluczowe;

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'

Użycie "new" przypisuje wartość" this " wewnątrz funkcji do zadeklarowana zmienna, podczas gdy jej nie używa, przypisuje wartość zwracaną.

 43
Author: Stephen Belanger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-10 21:54:28

I możesz go użyć do obsługi błędów i debugowania, jak to:

try{
    somefunction();
} 
catch(error){
    if (error instanceof TypeError) {
        // Handle type Error
    } else if (error instanceof ReferenceError) {
        // Handle ReferenceError
    } else {
        // Handle all other error types
    }
}
 8
Author: tito11,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-22 11:00:28
//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
Author: yfeldblum,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-15 18:08:35

Na pytanie " Kiedy jest to właściwe, a kiedy nie?", moje 2 grosze:

instanceof jest rzadko użyteczny w kodzie produkcyjnym, ale przydatny w testach, w których chcesz upewnić się, że Twój KOD Zwraca / tworzy obiekty właściwego typu. Mówiąc wprost o rodzajach obiektów zwracanych / tworzonych przez Twój kod, twoje testy stają się potężniejsze jako narzędzie do zrozumienia i dokumentowania kodu.

 1
Author: Andrew Magee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-24 02:01:49

instanceof jest tylko cukrem składniowym dla 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 zależy tylko od prototypu konstruktora obiektu.

Konstruktor jest zwykłą funkcją. Ściśle mówiąc jest to obiekt funkcyjny, ponieważ wszystko jest obiektem w Javascript. A ten obiekt funkcji ma prototyp, ponieważ każda funkcja ma prototyp.

Prototyp jest zwykłym obiektem, który znajduje się w łańcuchu prototypów innego obiektu. Czyli bycie w prototype chain of another object makes a object to a prototype:

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

Operator instanceof powinien być unikany, ponieważ fałszuje klasy, które nie istnieją w Javascript. Pomimo słowa kluczowego class nie w ES2015, ponieważ {[6] } jest znowu tylko składniowy cukier dla...ale to już inna historia.

 1
Author: ftor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-26 21:16:57
Co to jest?

Javascript jest językiem prototypowym, co oznacza, że używa prototypów do "dziedziczenia". operator instanceof sprawdza, czy typ właściwości konstruktora prototype jest obecny w łańcuchu __proto__ obiektu. Oznacza to, że zrobi to co następuje (zakładając, że testObj jest obiektem funkcji):

obj instanceof testObj;
  1. sprawdź, czy prototyp obiektu jest równy prototypowi konstruktora: obj.__proto__ === testObj.prototype > > jeśli jest to true instanceof powróci true.
  2. / Align = "left" / Na przykład: obj.__proto__.__proto__ === testObj.prototype > > jeśli jest to true instanceof powróci true.
  3. powtórzy Krok 2, dopóki nie zostanie sprawdzony pełny prototyp obiektu. Jeśli nigdzie w łańcuchu prototypów obiektu nie jest dopasowane do testObj.prototype, to instanceof operator zwróci false.

Przykład:

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

Jakie problemy rozwiązuje?

Rozwiązał problem wygodnego sprawdzania, czy obiekt wywodzi się z pewnego prototypu. Na przykład, gdy funkcja otrzymuje obiekt, który może mieć różne prototypy. Następnie, przed użyciem metod z łańcucha prototypów, możemy użyć operatora instanceof, aby sprawdzić, czy te metody znajdują się na obiekcie.

Przykład:

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);

Tutaj w talk() funkcja najpierw jest sprawdzana, czy prototyp znajduje się na obiekcie. Następnie wybiera się odpowiednią metodę do wykonania. Nie wykonanie tego czeku może powoduje wykonanie metody, która nie istnieje, a tym samym błąd odniesienia.

Kiedy jest to właściwe, a kiedy nie?
Już to przerabialiśmy. Użyj go, gdy potrzebujesz sprawdzić prototyp obiektu przed zrobieniem czegoś z nim.
 1
Author: Willem van der Veen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-05 11:10:47

Właśnie znalazłem aplikację w realnym świecie i myślę, że będę z niej częściej korzystać.

Jeśli używasz zdarzeń jQuery, czasami chcesz napisać bardziej ogólną funkcję, która może być również wywoływana bezpośrednio (bez zdarzenia). Możesz użyć instanceof, aby sprawdzić, czy pierwszy parametr twojej funkcji jest instancją jQuery.Event i odpowiednio zareagować.

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

W moim przypadku funkcja potrzebna do obliczenia czegoś albo dla wszystkich (poprzez kliknięcie przycisku), albo tylko dla jednego konkretnego elementu. Kod Użyłem:

var recalc = function (el) { 
    el = (el == undefined || el instanceof $.Event) ? $('span.allItems') : $(el);
    // calculate...
};
 0
Author: jussty,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-26 12:18:16