web-dev-qa-db-fra.com

Pourquoi, en JavaScript, "Object instanceof Function" et "Function instanceof Object" renvoient-ils true?

Pourquoi, dans JavaScript, Object instanceof Function et Function instanceof Object renvoient-ils true?

Je l'ai essayé dans Safari WebInspector.

33
dinghao

J'ai mis du temps à comprendre, mais ça vaut vraiment le temps passé. Tout d’abord, voyons comment fonctionne instanceof.

Citant de MDN ,

L'opérateur instanceof teste si un objet a dans sa chaîne de prototypes la propriété prototype d'un constructeur.

[instanceof]

Voyons maintenant comment instanceof est défini par la spécification ECMA 5.1,

Le RelationalExpression: RelationalExpression instanceof ShiftExpression de production est évalué comme suit:

  1. Soit lref le résultat de l’évaluation de RelationalExpression.
  2. Soit lval être GetValue(lref).
  3. Soit rref le résultat de l’évaluation de ShiftExpression.
  4. Soit rval être GetValue(rref).
  5. Si Type(rval) n'est pas un objet, générez une exception TypeError.
  6. Si rval n'a pas de méthode interne [[HasInstance]], lève une exception TypeError.
  7. Renvoie le résultat de l'appel de la méthode interne [[HasInstance]] de rval avec l'argument lval.

D'abord, les expressions de gauche et de droite sont évaluées (GetValue), puis le résultat de droite devrait être un objet avec une méthode interne [[HasInstance]]. Tous les objets n'auront pas la méthode interne [[HasInstance]], mais des fonctions. Par exemple, ce qui suit va échouer

console.log(Object instanceof {});
# TypeError: Expecting a function in instanceof check, but got #<Object>

[[HasInstance]]

Voyons maintenant comment [[HasInstance]] a été défini dans la spécification ECMA 5.1,

Supposons que F soit un objet Function.

Lorsque la méthode interne [[HasInstance]] de F est appelée avec la valeur V, les étapes suivantes sont entreprises:

  1. Si V n'est pas un objet, retournez false.
  2. Soit O le résultat de l'appel de la méthode interne [[Get]] de F avec le nom de propriété "prototype".
  3. Si Type(O) n'est pas un objet, générez une exception TypeError.
  4. Répéter 
    1. Soit V la valeur de la propriété [[Prototype]] internal de V.
    2. Si V est null, retournez false.
    3. Si O et V se rapportent au même objet, retournez true.

C'est si simple. Prenez la propriété prototype de F et comparez-la avec la propriété [[Prototype]] internal de O jusqu'à ce qu'elle devienne null ou prototype de F soit identique à O.

[[prototype]] propriété interne

Voyons d’abord quelle est la propriété [[prototype]] internal ,

Tous les objets ont une propriété interne appelée [[Prototype]]. La valeur de cette propriété est null ou un objet et est utilisée pour implémenter l'héritage. Le fait qu'un objet natif puisse ou non avoir un objet hôte en tant que [[Prototype]] dépend de l'implémentation. Chaque chaîne [[Prototype]] doit avoir une longueur finie (c’est-à-dire que, à partir de tout objet, l’accès récursif à la propriété interne [[Prototype]] doit finalement conduire à une valeur null).

Remarque: Nous pouvons obtenir cette propriété interne avec la fonction Object.getPrototypeOf .

prototype property

[[HasInstance]] parle également d'une autre propriété appelée prototype , qui est spécifique aux objets Function.

La valeur de la propriété prototype est utilisée pour initialiser la propriété [[Prototype]] internal d'un objet nouvellement créé avant que l'objet Function ne soit appelé en tant que constructeur pour cet objet nouvellement créé. 

Cela signifie que, lorsqu'un objet fonction est utilisé en tant que constructeur, un nouvel objet est créé et le nouvel objet a son [[Prototype]] interne initialisé avec cette propriété prototype. Par exemple,

function Test() {}
Test.prototype.print = console.log;
console.log(Object.getPrototypeOf(new Test()) === Test.prototype);
# true

Problème actuel

Revenons maintenant à la question même. Permet de prendre le premier cas

console.log(Object instanceof Function);
# true

Il va d'abord chercher Function.prototype et il va essayer de trouver si cet objet est dans la hiérarchie prototype de Object. Voyons comment cela se passe

console.log(Function.prototype);
# [Function: Empty]
console.log(Object.getPrototypeOf(Object));
# [Function: Empty]
console.log(Object.getPrototypeOf(Object) === Function.prototype);
# true

Puisque le Function.prototype correspond à la propriété interne de Object, [[Prototype]], il retourne true.

Prenons maintenant le deuxième cas

console.log(Function instanceof Object);
# true
console.log(Object.prototype);
# {}
console.log(Object.getPrototypeOf(Function));
# [Function: Empty]
console.log(Object.getPrototypeOf(Function) === Object.prototype);
# false
console.log(Object.getPrototypeOf(Object.getPrototypeOf(Function)));
# {}
Object.getPrototypeOf(Object.getPrototypeOf(Function)) === Object.prototype
# true

Ici, nous obtenons d’abord le Object.prototype, qui est {}. Maintenant, il essaie de trouver si le même objet {} est présent dans la chaîne de prototypes de Function. Le parent immédiat de Function est et la fonction vide.

console.log(Object.getPrototypeOf(Function));
# [Function: Empty]

Ce n'est pas la même chose que Object.prototype

console.log(Object.getPrototypeOf(Function) === Object.prototype);
# false

Mais l'algorithme [[HasInstance]] ne s'arrête pas là. Il répète et monte d'un niveau

console.log(Object.getPrototypeOf(Object.getPrototypeOf(Function)));
# {}

Et ceci est identique à Object.prototype. C'est pourquoi cela retourne true.

37
thefourtheye

De MDN :

L'opérateur instanceof teste si un objet a dans sa chaîne de prototypes la propriété de prototype d'un constructeur.

Essentiellement, il vérifie si Object (pas une instance de Object, mais le constructeur lui-même) a comme instance de Function.constructor quelque part dans sa chaîne de prototypes.

Et en effet:

> Function.__proto__.__proto__ === Object.prototype
true
> Object.__proto__ === Function.prototype
true

Ceci explique pourquoi Object instanceof Function et l'inverse.

14
Andrew Eisenberg

TOUS les objets ont une propriété interne appelée [[Prototype]]. La valeur de cette propriété est null ou un objet et est utilisée pour implémenter l'héritage. Si vous essayez de rechercher une clé sur un objet et que celui-ci est introuvable, JavaScript le recherchera dans la chaîne de prototypes.

Le constructeur de fonctions crée de nouveaux objets de fonction (instances du constructeur de fonctions). La propriété prototype est spécifique aux objets Function. Le constructeur de fonction est lui-même un objet Function (instance du constructeur de fonction).

Lorsqu'un objet Function est utilisé en tant que constructeur, un nouvel objet est créé et son objet [[Prototype]] est initialisé avec la propriété prototype du constructeur.

function Dog () {}
var myCrazyDog = new Dog();
myCrazyDog.__proto__ === Dog.prototype // true

La spécification de langage est que tous les objets sont des instances du constructeur Object et que toutes les fonctions sont des instances du constructeur Function.

L'objet instanceof Function est vrai car Object est une fonction et constitue donc une instance de Function (Object est un objet Function - une instance du constructeur de la fonction). L'objet hérite de Function.prototype.

console.log(Object instanceof Function)                         // true
console.log(Object.__proto__ === Function.prototype)            // true

Object instanceof Object est vrai car Object hérite de Function.prototype. Puisque Function.prototype est un objet, il hérite de Object.prototype. L'instance de fonction de Object est true car Function hérite de Function.prototype. Comme Function.prototype est un objet, il hérite de Object.prototype. La chaîne de prototypes ressemble à ceci:

Object ---> Function.prototype ---> Object.prototype ---> null
Function ---> Function.prototype ---> Object.prototype ---> null

console.log(Object instanceof Object)                               // true
console.log(Object.__proto__ === Function.prototype)                // true
console.log(Object.__proto__.__proto__ === Object.prototype)        // true
console.log(Function instanceof Object)                             // true
console.log(Function.__proto__ === Function.prototype)              // true
console.log(Function.__proto__.__proto__ === Object.prototype)      // true

Fonction instanceof Fonction est vraie . Function est une instance de lui-même (naturellement, car c’est une fonction, et donc une instance de Function). La chaîne de prototype ressemble à ceci:

Function ---> Function.prototype ---> Object.prototype ---> null

console.log(Function instanceof Function)                           // true
console.log(Function.__proto__ === Function.prototype)              // true
console.log(Function.__proto__.__proto__ === Object.prototype)      // true

Gardez donc à l’esprit que les constructeurs Function () et Object () sont des fonctions. Comme ce sont des fonctions, elles sont des instances du constructeur Function () et héritent de Function.prototype. Puisque Function.prototype est un objet, Function.prototype est une instance de Object, héritant donc de Object.prototype.

console.log(Object instance of Function)                    // true
console.log(Function instance of Function)                  // true
console.log(Function.prototype instanceof Object);          // true
6
misterd89

La source de confusion dans votre question réside dans la double nature inhérente des fonctions * en JavaScript (ECMAScript). 

Les fonctions en js sont à la fois des fonctions normales et des objets en même temps. Considérez-les comme des algorithmes Dr. Jekyll et Mr. Hyde . Ils ressemblent à des objets à l’extérieur, mais à l’intérieur, ce ne sont que vos bonnes vieilles fonctions js avec toutes leurs bizarreries, ou peut-être que c’est l’inverse!

JavaScript est vraiment une affaire délicate :)

Revenons donc à votre question, en empruntant la syntaxe apparaissant sur MDN: 

object instanceof constructor 

En l'appliquant à la première instruction de votre code: 

Object instanceof Function

Ici, vous avez Object, une fonction constructeur utilisée en tant qu'initialiseur d'objet, mais puisque les fonctions mènent une double vie en js, elle est associée à des propriétés et à des méthodes propres à chaque objet, ce qui en fait également un objet. 

La première condition de la déclaration a donc été remplie. Nous restons à enquêter sur l'autre condition ou l'opérande. 

Function, comme vous l'avez peut-être remarqué, est également un constructeur de fonctions, mais son autre objet, ne nous intéresse plus pour le moment de l'exécution de cette instruction particulière. 

Ainsi, les conditions syntaxiques sont toutes deux remplies à savoir "objet" et "constructeur". Nous pouvons maintenant procéder à l’enquête sur leur relation héréditaire et s’il existe un lien entre eux. 

Étant donné que Object est une fonction fonctionnelle en soi, il est tout à fait logique de supposer que son prototype interne indique la référence d'objet Function.prototype puisque, dans jsALLfunctions inherit leurs accessoires et méthodes à travers ce même emplacement Function.prototype

true est définitivement leSEULrésultat attendu de cette comparaison effectuée par l'opérateur instanceof.

Pour l'autre cas: 

Function instanceof Object

Depuis que nous avons déjà établi que les fonctions dans js ont aussi un côté objet. Il est logique qu'ils aient obtenu leurs fantaisie spécifiques aux objets toys du Object.prototype et qu'ils constituent donc instances du constructeur Object. 

J'espère que je n'ai pas ajouté à la confusion avec mes explications et allégories. :) 

*: Non seulement les fonctions qui mènent une double vie en js. Presque tous les types de données dans js ont un côté obscur qui facilite la réalisation d'opérations et de manipulations sans tracas.

3
Mr. X

La propriété la plus redoutable est en fait que Function est une instance de lui-même. Function instanceof Function renvoie vrai.

Il est bien expliqué dans - Le modèle de type Javascript étonnamment élégant , sur http://web.archive.org/web/20140205182624/http://vijayan.ca/blog/2012/02/ 21/javascript-type-model

Citez à la fin de l'explication:

Oui, cela signifie que Function est une instance de lui-même (naturellement, car c’est une fonction, et donc une instance de Function). C’est quelque chose avec lequel nous avons tous affaire, en connaissance de cause ou non, depuis longtemps - toutes les fonctions du constructeur sont des fonctions régulières et donc des instances de Function, et Function elle-même est simplement la fonction constructeur pour la construction d’autres fonctions. une instance de Function.

 enter image description here

1
Aurélien Ribon

Explication très simple, différente de toutes les réponses

Les deux objets Object et Function sont des constructeurs (type des deux avec retour "objets Function") et sont tous deux créés à partir de Function Constructor. La propriété __proto__ de ces deux éléments pointe vers l'objet 'Function.prototype'.

EXPLICATION RAPIDE: La propriété __proto__ d'un objet (disons p1 qui est un type de personne) pointe sur le prototype du constructeur (disons Person.prototype) De nouveau, __proto__ dans la chaîne de prototypes pointe sur l'objet "Object.prototype".

AVANT DE LIRE D'AUTRES DÉTAILS IMPRIMÉS SUR LA CONSOLE CHROME console.dir (Object), console.dir (Fonction)

KEEP IN MIND, les constructeurs de fonctions et les objets vous permettront de voir les propriétés .prototype et __proto__. Dans tous les objets d'instance (disons p1), vous ne trouverez que la propriété __proto__. __Proto__ est l'accesseur de la propriété masquée [[Prototye]] et le meilleur moyen d'obtenir est Object.getPrototypeOf (p1) car __proto__ est protégé.

(p1 instanceof Person) L'opérateur vérifie ici si le prototype de la personne constructeur se trouve dans la chaîne de prototypes de l'objet p1. notez que la première valeur est un objet d'instance (p1) et que la deuxième valeur est un constructeur (Personne).

Permet d'analyser => Instance de fonction de l'objet.

__Proto __.__ proto__ de l'objet de fonction pointe sur Object.prototype, il est donc vrai

Permet d'analyser => Instance d'objet de fonction.

__Proto__ de l'objet object pointe sur Function.prototype, il est donc vrai

J'espère que cela t'aides.

0
Sumer