web-dev-qa-db-fra.com

Pourquoi utiliser Object.prototype.hasOwnProperty.call (myObj, prop) au lieu de myObj.hasOwnProperty (prop)?

Si je comprends bien, chaque objet en Javascript hérite du prototype Object, ce qui signifie que chaque objet en Javascript a accès à la fonction hasOwnProperty via sa chaîne de prototypes.

En lisant le code source de require.js, je suis tombé sur cette fonction:

function hasProp(obj, prop) {
    return hasOwn.call(obj, prop);
}

hasOwn est une référence à Object.prototype.hasOwnProperty. Y a-t-il une différence pratique à écrire cette fonction comme

function hasProp(obj, prop) {
    return obj.hasOwnProperty(prop);
}

Et puisque nous y sommes, pourquoi définissons-nous cette fonction? Est-ce juste une question de raccourcis et de mise en cache locale de l'accès à la propriété pour de (légers) gains de performances, ou ai-je raté des cas où hasOwnProperty pourrait être utilisé sur des objets qui n'ont pas cette méthode?

78
timkg

Y a-t-il une différence pratique [entre mes exemples]?

L'utilisateur peut avoir un objet JavaScript créé avec Object.create(null), qui aura une chaîne null[[Prototype]], Et par conséquent, hasOwnProperty() ne sera pas disponible sur il. L'utilisation de votre deuxième formulaire ne fonctionnerait pas pour cette raison.

C'est aussi une référence plus sûre à Object.prototype.hasOwnProperty() (et aussi plus courte).

Vous pouvez imaginer que quelqu'un a pu faire ...

var someObject = {
    hasOwnProperty: function(lol) {
        return true;
    }
};

Ce qui ferait échouer une hasProp(someObject) si elle avait été implémentée comme votre deuxième exemple (elle trouverait cette méthode directement sur l'objet et l'invoquerait, au lieu d'être déléguée à Object.prototype.hasOwnProperty).

Mais il est moins probable que quelqu'un ait outrepassé la référence Object.prototype.hasOwnProperty.

Et puisque nous y sommes, pourquoi définissons-nous cette fonction?

Voir au dessus.

Est-ce juste une question de raccourcis et de mise en cache locale de l'accès à la propriété pour de (légers) gains de performances ...

Cela peut le rendre plus rapide en théorie, car la chaîne [[Prototype]] N'a pas à être suivie, mais je soupçonne que cela est négligeable et pas la raison pour laquelle l'implémentation est pourquoi.

... ou est-ce que je manque des cas où hasOwnProperty pourrait être utilisé sur des objets qui n'ont pas cette méthode?

hasOwnProperty() existe sur Object.prototype, mais peut être remplacé. Chaque objet JavaScript natif (mais les objets Host ne sont pas garantis de suivre cela, voir l'explication détaillée de RobG ) a Object.prototype Comme dernier objet de la chaîne avant null (sauf bien sûr pour l'objet retourné par Object.create(null)).

89
alex

Si je comprends bien, chaque objet en Javascript hérite du prototype d'objet

Cela peut sembler séparer les cheveux, mais il existe une différence entre javascript (le terme générique pour les implémentations ECMAScript) et ECMAScript (le langage utilisé pour les implémentations javascript). C'est ECMAScript qui définit un schéma d'héritage, pas javascript, donc seuls les objets ECMAScript natifs doivent implémenter ce schéma d'héritage.

Un programme javascript en cours d'exécution comprend au moins les objets ECMAScript intégrés (objet, fonction, nombre, etc.) et probablement certains objets natifs (par exemple des fonctions). Il peut également contenir certains objets Host (tels que des objets DOM dans un navigateur ou d'autres objets dans d'autres environnements Host).

Alors que les objets intégrés et natifs doivent implémenter le schéma d'héritage défini dans ECMA-262, les objets hôtes ne le font pas. Par conséquent, tous les objets dans un environnement javascript must héritent de Object.prototype . Par exemple, les objets Host dans IE implémentés en tant qu'objets ActiveX lèveront des erreurs s'ils sont traités comme des objets natifs (d'où pourquoi try..catch est utilisé pour initialiser les objets MS XMLHttpRequest). Certains objets DOM (comme NodeLists in IE in quirks mode) si passé aux méthodes Array, des erreurs seront générées, les objets DOM dans IE 8 et inférieurs n'ont pas de schéma d'héritage de type ECMAScript, etc.

Par conséquent, il ne faut pas supposer que tous les objets d'un environnement javascript héritent de Object.prototype.

ce qui signifie que chaque objet en Javascript a accès à la fonction hasOwnProperty via sa chaîne prototype

Ce qui n'est pas vrai pour certains objets Host en IE en mode bizarreries (et IE 8 et inférieur toujours) au moins).

Compte tenu de ce qui précède, il vaut la peine de se demander pourquoi un objet peut avoir sa propre méthode hasOwnProperty et l'opportunité d'en appeler une autre hasOwnProperty à la place sans d'abord tester si c'est une bonne idée ou non.

Modifier

Je soupçonne que la raison de l'utilisation de Object.prototype.hasOwnProperty.call est que dans certains navigateurs, les objets Host n'ont pas de méthode hasOwnProperty , en utilisant call et la méthode intégrée est une alternative. Cependant, le faire de manière générique ne semble pas être une bonne idée pour les raisons mentionnées ci-dessus.

En ce qui concerne les objets hôtes, l'opérateur dans peut être utilisé pour tester les propriétés en général, par exemple.

var o = document.getElementsByTagName('foo');

// false in most browsers, throws an error in IE 6, and probably 7 and 8
o.hasOwnProperty('bar');

// false in all browsers
('bar' in o);

// false (in all browsers? Do some throw errors?)
Object.prototype.hasOwnProperty.call(o, 'bar');

Une alternative (testée dans IE6 et autres):

function ownProp(o, prop) {

  if ('hasOwnProperty' in o) {
    return o.hasOwnProperty(prop);

  } else {
    return Object.prototype.hasOwnProperty.call(o, prop);
  }
}

De cette façon, vous appelez uniquement spécifiquement le hasOwnProperty intégré là où l'objet ne l'a pas (hérité ou autre).

Cependant, si un objet n'a pas de méthode hasOwnProperty, il est probablement aussi approprié d'utiliser l'opérateur dans que l'objet probable n'a pas de schéma d'héritage et toutes les propriétés sont sur l'objet (c'est juste une supposition cependant), par exemple L'opérateur dans est un moyen courant (et apparemment réussi) de tester la prise en charge des propriétés DOM par les propriétés.

13
RobG

JavaScript ne protège pas le nom de la propriété hasOwnProperty

S'il existe la possibilité qu'un objet ait une propriété avec ce nom, il est nécessaire d'utiliser un hasOwnProperty externe pour obtenir des résultats corrects:

Vous pouvez copier-coller les extraits de code ci-dessous sur la console de votre navigateur pour mieux comprendre

var foo = {
  hasOwnProperty: function() {
    return false;
  },
  bar: 'I belong to foo'
};

Retourne toujours faux

foo.hasOwnProperty('bar'); // false

Utilisez hasOwnProperty d'un autre objet et appelez-le avec this défini sur foo

({}).hasOwnProperty.call(foo, 'bar'); // true

Il est également possible d'utiliser la propriété hasOwnProperty du prototype Object à cet effet

Object.prototype.hasOwnProperty.call(foo, 'bar'); // true
6
Sudharshan

Les informations fournies dans les deux réponses existantes sont parfaites. Cependant, l'utilisation de:

('propertyName' in obj)

est mentionné plusieurs fois. Il convient de noter que les implémentations hasOwnProperty ne retourneront true que si la propriété est directement contenue sur l'objet testé.

L'opérateur in inspectera également la chaîne du prototype.

Cela signifie que les propriétés d'instance retourneront true lorsqu'elles seront passées à hasOwnProperty où les propriétés du prototype retourneront false.

En utilisant l'opérateur in, les propriétés d'instance et de prototype renverront true.

1
steve