Pourquoi instanceof renvoie false pour certains littéraux?
-
03-07-2019 - |
Question
"foo" instanceof String //=> false
"foo" instanceof Object //=> false
true instanceof Boolean //=> false
true instanceof Object //=> false
false instanceof Boolean //=> false
false instanceof Object //=> false
// the tests against Object really don't make sense
Les littéraux de tableau et les littéraux d'objet correspondent ...
[0,1] instanceof Array //=> true
{0:1} instanceof Object //=> true
Pourquoi ne pas tous? Ou pourquoi ne pas tous pas ?
Et de quoi sont-ils une instance, alors?
C'est la même chose dans FF3, IE7, Opera et Chrome. Donc, au moins c'est cohérent.
Vous avez manqué quelques-uns.
12.21 instanceof Number //=> false
/foo/ instanceof RegExp //=> true
La solution
Les primitives sont d'un type différent des objets créés à partir de Javascript. Documents de l'API de Mozilla :
var color1 = new String("green");
color1 instanceof String; // returns true
var color2 = "coral";
color2 instanceof String; // returns false (color2 is not a String object)
Je ne trouve aucun moyen de construire des types primitifs avec du code, ce n'est peut-être pas possible. C’est probablement pour cette raison que les gens utilisent typeof " foo " === "chaîne"
au lieu de instance de
.
Une façon simple de se souvenir de choses comme celle-ci est de se demander: "Je me demande ce qui serait sain et facile à apprendre". Quelle que soit la réponse, Javascript fait autre chose.
Autres conseils
j'utilise:
function isString(s) {
return typeof(s) === 'string' || s instanceof String;
}
Parce qu'en JavaScript, les chaînes peuvent être des littéraux ou des objets.
En JavaScript, tout est un objet (ou peut au moins être traité comme un objet), sauf primitives (booléens, null, nombres, chaînes et la valeur undefined
(et le symbole dans ES6)):
console.log(typeof true); // boolean
console.log(typeof 0); // number
console.log(typeof ""); // string
console.log(typeof undefined); // undefined
console.log(typeof null); // object
console.log(typeof []); // object
console.log(typeof {}); // object
console.log(typeof function () {}); // function
Comme vous pouvez le voir, les tableaux et la valeur null
sont tous des objets considérés ( null
est une référence à un objet qui n'existe pas). Les fonctions sont distinguées car elles constituent un type spécial d’objets appelables . Cependant, ce sont toujours des objets.
D'autre part, les littéraux true
, 0
, ""
" et non défini
ne sont pas des objets. . Ce sont des valeurs primitives en JavaScript. Toutefois, les booléens, les nombres et les chaînes ont également les constructeurs Boolean
, Number
et String
qui enveloppent leurs primitives respectives pour fournir une fonctionnalité supplémentaire:
console.log(typeof new Boolean(true)); // object
console.log(typeof new Number(0)); // object
console.log(typeof new String("")); // object
Comme vous pouvez le constater lorsque des valeurs primitives sont encapsulées dans les constructeurs Boolean
, Number
et String
, elles deviennent des objets. L'opérateur instanceof
ne fonctionne que pour les objets (c'est pourquoi il renvoie false
pour les valeurs primitives):
console.log(true instanceof Boolean); // false
console.log(0 instanceof Number); // false
console.log("" instanceof String); // false
console.log(new Boolean(true) instanceof Boolean); // true
console.log(new Number(0) instanceof Number); // true
console.log(new String("") instanceof String); // true
Comme vous pouvez le voir, typeof
et instance de
ne suffisent pas pour vérifier si une valeur est un booléen, un nombre ou une chaîne - typeof
ne fonctionne que pour les booléens primitifs, les nombres et les chaînes; et instanceof
ne fonctionne pas pour les booléens, les nombres et les chaînes primitifs.
Heureusement, il existe une solution simple à ce problème. L'implémentation par défaut de toString
(c'est-à-dire telle qu'elle est définie de manière native sur Object.prototype.toString
) renvoie la propriété interne [[Class]]
des deux. valeurs et objets primitifs:
function classOf(value) {
return Object.prototype.toString.call(value);
}
console.log(classOf(true)); // [object Boolean]
console.log(classOf(0)); // [object Number]
console.log(classOf("")); // [object String]
console.log(classOf(new Boolean(true))); // [object Boolean]
console.log(classOf(new Number(0))); // [object Number]
console.log(classOf(new String(""))); // [object String]
La propriété interne [[Class]]
d'une valeur est beaucoup plus utile que la typeof
de la valeur. Nous pouvons utiliser Object.prototype.toString
pour créer notre propre version (plus utile) de l'opérateur typeof
comme suit:
function typeOf(value) {
return Object.prototype.toString.call(value).slice(8, -1);
}
console.log(typeOf(true)); // Boolean
console.log(typeOf(0)); // Number
console.log(typeOf("")); // String
console.log(typeOf(new Boolean(true))); // Boolean
console.log(typeOf(new Number(0))); // Number
console.log(typeOf(new String(""))); // String
J'espère que cet article vous a aidé. Pour en savoir plus sur les différences entre les primitives et les objets encapsulés, lisez le billet suivant: > La vie secrète des primitifs JavaScript & nbsp; Primitives
Vous pouvez utiliser la propriété du constructeur:
'foo'.constructor == String // returns true
true.constructor == Boolean // returns true
typeof(text) === 'string' || text instanceof String;
vous pouvez l'utiliser, cela fonctionnera pour les deux cas comme
-
var text = "toto";
// typeof fonctionnera -
String text = new String ("toto");
// instanceof fonctionnera
Je pense avoir mis au point une solution viable:
Object.getPrototypeOf('test') === String.prototype //true
Object.getPrototypeOf(1) === String.prototype //false
Ceci est défini dans la spécification ECMAScript Section 7.3.19 Étape 3 : Si le type (O) n'est pas un objet, renvoyez false.
En d'autres termes, si le Obj
dans Obj instance of Callable
n'est pas un objet, le instance of
sera court-circuité à . false
directement.
https://www.npmjs.com/package/typeof
Renvoie une représentation sous forme de chaîne de instance de
(nom du constructeur)
function instanceOf(object) {
var type = typeof object
if (type === 'undefined') {
return 'undefined'
}
if (object) {
type = object.constructor.name
} else if (type === 'object') {
type = Object.prototype.toString.call(object).slice(8, -1)
}
return type.toLowerCase()
}
instanceOf(false) // "boolean"
instanceOf(new Promise(() => {})) // "promise"
instanceOf(null) // "null"
instanceOf(undefined) // "undefined"
instanceOf(1) // "number"
instanceOf(() => {}) // "function"
instanceOf([]) // "array"
Pour moi, la confusion causée par
"str".__proto__ // #1
=> String
So " str " istanceof String
doit renvoyer true
, car comment istanceof fonctionne comme ci-dessous:
"str".__proto__ == String.prototype // #2
=> true
Les résultats de l'expression n ° 1 et n ° 2 sont contradictoires. Par conséquent, l'un d'entre eux doit être erroné.
# 1 est faux
Je découvre que cela est dû à la propriété non standard de __ proto __
. Vous devez donc utiliser la propriété standard: Object.getPrototypeOf
Object.getPrototypeOf("str") // #3
=> TypeError: Object.getPrototypeOf called on non-object
Désormais, il n'y a plus de confusion entre l'expression n ° 2 et n ° 3
.Ou vous pouvez simplement créer votre propre fonction comme suit:
function isInstanceOf(obj, clazz){
return (obj instanceof eval("("+clazz+")")) || (typeof obj == clazz.toLowerCase());
};
utilisation:
isInstanceOf('','String');
isInstanceOf(new String(), 'String');
Ceux-ci doivent tous deux renvoyer la valeur true.