51 votes

Quelle est la différence entre isPrototypeOf et instanceof en Javascript ?

Dans certains de mes anciens codes, j'utilise ce qui suit :

Object.prototype.instanceOf = function( iface )
{
 return iface.prototype.isPrototypeOf( this );
};

Ensuite, je fais (par exemple)

[].instanceOf( Array )

Cela fonctionne, mais il semble que ce qui suit ferait la même chose :

[] instanceof Array

Il ne s'agit là que d'un exemple très simple. Ma question est donc la suivante :

Est a instanceof b TOUJOURS la même chose que b.prototype.isPrototypeOf(a) ?

0 votes

Bien que vous puissiez toujours utiliser instanceof (avec des constructeurs en RHS), tous les objets ne peuvent pas hériter de Object.prototype . Object.create(null) instanceof Something y ({}).instanceOf({prototype:Something.prototype}) fonctionnera (et donnera false ) où l'inverse échouerait.

32voto

CMS Points 315406

Oui, ils font la même chose, ils parcourent tous deux la chaîne des prototypes à la recherche d'un objet spécifique dans celle-ci.

La différence entre les deux est ce qu'ils sont et la manière dont vous les utilisez, par exemple, la isPrototypeOf es une fonction disponible sur le Object.prototype il vous permet de tester si un objet spécifique se trouve dans la chaîne de prototypes d'une autre, puisque cette méthode est définie sur Object.prototype il est disponible pour tous les objets.

instanceof es un opérateur et il attend deux opérandes, un objet et une variable de type Fonction de construction il testera si la fonction passée prototype existe sur la chaîne de l'objet (via la propriété [[HasInstance]](V) opération interne, disponible uniquement dans les objets Fonction).

Par exemple :

function A () {
  this.a = 1;
}
function B () {
  this.b = 2;
}
B.prototype = new A();
B.prototype.constructor = B;

function C () {
  this.c = 3;
}
C.prototype = new B();
C.prototype.constructor = C;

var c = new C();

// instanceof expects a constructor function

c instanceof A; // true
c instanceof B; // true
c instanceof C; // true

// isPrototypeOf, can be used on any object
A.prototype.isPrototypeOf(c); // true
B.prototype.isPrototypeOf(c); // true
C.prototype.isPrototypeOf(c); // true

1 votes

Donc, la seule différence est que je peux utiliser isPrototypeOf, si je n'ai que le prototype, alors que j'ai besoin du constructeur pour instanceof ? (Ce qui rend ma fonction réellement identique à instanceof ?)

1 votes

Votre réponse textuelle est utile, votre exemple de code l'est moins. (Il ne montre que des aspects égaux mais pas de différences.) Cependant, il soulève une autre question pour moi : A quoi sert ".constructor" ? J'ai vu un tel code à certains endroits, mais je ne l'ai jamais écrit moi-même et je ne semble pas en avoir eu besoin. (J'avais généralement quelque chose comme C.prototype.clazz = C; difficile.) Pourquoi les gens définissent-ils le constructeur ?

1 votes

@Steffen Heil : le code écrit par CMS est assez clair je pense, il utilise la manière la plus simple et la plus connue (bien que ce ne soit pas la plus efficace) d'hériter en JavaScript entre les constructeurs. Essayez de supprimer la ligne B.prototype.constructor = B et inspecter le constructeur d'une instance de B : alert((new B).constructor) et vous verrez le constructeur de la fonction A. En faisant cela, il s'assure de trouver, comme constructeur de toutes les instances de B, uniquement B.

8voto

Oliver Sieweke Points 982

Est a instanceof b TOUJOURS la même chose que b.prototype.isPrototypeOf(a) ?

Non, a instanceof b ne se comportera pas toujours de la même manière que b.prototype.isPrototypeOf(a) .

Réponse de la CMS a souligné qu'ils diffèrent dans ce qu'ils sont (l'un est un opérateur et l'autre est une méthode intégrée disponible sur l'objet Object.prototype objet). C'est correct, mais il y a aussi des cas particuliers pour lesquels la fonction a instanceof b se traduira par un TypeError tandis que b.prototype.isPrototypeOf(a) fonctionnera très bien et vice versa.

Différence 1

Le côté droit de instanceof est censé être une fonction de construction.

Si b n'est pas une fonction :

  • a instanceof b se traduira par un TypeError .

  • b.prototype.isPrototypeOf(a) fonctionnera très bien.

    const b = { prototype: {} }; const a = Object.create( b.prototype );

    console.log( b.prototype.isPrototypeOf(a) ); // true console.log( a instanceof b ); // TypeError: Right-hand side of 'instanceof' is not callable

Différence n°2

Lorsque vous utilisez b.prototype.isPrototypeOf(a) , b.prototype devrait hériter de Object.prototype :

Si b.prototype n'a pas accès à la Object.prototype.isPrototypeOf() méthode :

  • b.prototype.isPrototypeOf(a) se traduira par un TypeError .
  • a instanceof b fonctionnera très bien.

    function B() {}; B.prototype = Object.create( null );

    const a = new B();

    console.log( a instanceof B ); // true console.log( B.prototype.isPrototypeOf(a) ) // TypeError: B.prototype.isPrototypeOf is not a function

Différence n°3

Si le côté droit de instanceof est une fonction liée, elle est traitée de manière équivalente à sa fonction cible.

Si b est une fonction liée :

  • a instanceof b fonctionnera très bien.
  • b.prototype.isPrototypeOf(a) se traduira par un TypeError (les fonctions liées n'ont pas de prototype propriété).

    function B() {}; const BoundB = B.bind( null ); const a = new B();

    console.log( a instanceof BoundB ); // true console.log( BoundB.prototype.isPrototypeOf(a) ) // TypeError: Cannot read property 'isPrototypeOf' of undefined

Conclusion

  • Si vous avez affaire à un héritage prototypique établi par l'intermédiaire de Object.create() sans l'utilisation de constructeurs, vous devriez probablement utiliser la fonction Object.prototype.isPrototypeOf() (en effet, les cas d'utilisation de la méthode instanceof sont plus restreints en ce sens que instanceof s'attend à ce que son paramètre du côté droit soit une fonction constructeur).
  • Si vous avez affaire à des constructeurs, vous serez légèrement plus en sécurité en utilisant l'option instanceof (vous serez en mesure de couvrir les fonctions liées ainsi que les cas dans lesquels Object.prototype ne se trouve pas dans la chaîne des prototypes de Constructor.prototype ).

2voto

Paul Sweatte Points 8668

La préséance et la véracité des opérateurs diffèrent puisque l'un est une expression et l'autre un appel de méthode. Une chose à souligner est que les deux parcourir la chaîne des prototypes Vous ne pouvez donc pas supposer qu'il existe une correspondance biunivoque entre un prototype correspondant et l'objet en question :

var i = 0;

function foo()
{
console.log("foo");
console.log(i++ + ": " + Object.prototype.isPrototypeOf(Object) ) //true
console.log(i++ + ": " + Function.prototype.isPrototypeOf(Function) ) //true

console.log(i++ + ": " + Function.prototype.isPrototypeOf(Function) ) //true
console.log(i++ + ": " + Function.prototype.isPrototypeOf(Object) ) //true

console.log(i++ + ": " + RegExp.prototype.isPrototypeOf( RegExp(/foo/) ) ) //true
console.log(i++ + ": " + Object.prototype.isPrototypeOf( RegExp(/foo/) ) ) //true
console.log(i++ + ": " + Function.prototype.isPrototypeOf( RegExp(/foo/) ) ) //false
console.log(i++ + ": " + Object.prototype.isPrototypeOf(Math) ) //true
console.log(i++ + ": " + Math.isPrototypeOf(Math) ) //false
}

function bar()
{
console.log("bar");
console.log(i++ + ": " + (Object instanceof Object) ) //true

console.log(i++ + ": " + (Function instanceof Function) ) //true
console.log(i++ + ": " + (Function instanceof Object) ) //true

console.log(i++ + ": " + (RegExp(/foo/) instanceof RegExp) ) //true
console.log(i++ + ": " + (RegExp(/foo/) instanceof Object)  ) //true
console.log(i++ + ": " + (RegExp(/foo/) instanceof Function) ) //false
console.log(i++ + ": " + (Math instanceof Object) ) //true
console.log(i++ + ": " + (Math instanceof Math) ) //error
}
try
  {
  foo()
  }
catch(e)
  {
  console.log(JSON.stringify(e));
  }
finally
  {
  try
    {
    bar();
    }
  catch(e)
    {
    console.log(JSON.stringify(e));
    }
  }

Références

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X