Perché instanceof restituisce false per alcuni letterali?
-
03-07-2019 - |
Domanda
"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
I letterali dell'array e i letterali degli oggetti corrispondono ...
[0,1] instanceof Array //=> true
{0:1} instanceof Object //=> true
Perché non tutti? Oppure, perché non tutti non ?
E allora di cosa sono un'istanza?
È lo stesso in FF3, IE7, Opera e Chrome. Quindi, almeno è coerente.
Ne sono mancati alcuni.
12.21 instanceof Number //=> false
/foo/ instanceof RegExp //=> true
Soluzione
I primitivi sono di un tipo diverso rispetto agli oggetti creati da Javascript. Dai Documenti API 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)
Non riesco a trovare un modo per costruire tipi primitivi con il codice, forse non è possibile. Questo è probabilmente il motivo per cui le persone usano typeof " foo " === " string "
anziché instanceof
.
Un modo semplice per ricordare cose come questa è chiederti "mi chiedo cosa sarebbe sano e facile da imparare"? Qualunque sia la risposta, Javascript fa l'altra cosa.
Altri suggerimenti
Uso:
function isString(s) {
return typeof(s) === 'string' || s instanceof String;
}
Perché in JavaScript le stringhe possono essere letterali o oggetti.
In JavaScript tutto è un oggetto (o almeno può essere trattato come un oggetto), tranne primitive (booleani, null, numeri, stringhe e il valore undefined
(e il simbolo in 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
Come puoi vedere gli oggetti, le matrici e il valore null
sono tutti considerati oggetti ( null
è un riferimento a un oggetto che non esiste). Le funzioni si distinguono perché sono un tipo speciale di oggetti richiamabili . Tuttavia sono ancora oggetti.
D'altra parte i letterali true
, 0
, " "
e undefined
non sono oggetti . Sono valori primitivi in ??JavaScript. Tuttavia, i numeri booleani, i numeri e le stringhe hanno anche i costruttori Boolean
, Number
e String
che avvolgono rispettivamente i loro rispettivi primitivi per fornire funzionalità aggiuntive:
console.log(typeof new Boolean(true)); // object
console.log(typeof new Number(0)); // object
console.log(typeof new String("")); // object
Come puoi vedere quando i valori primitivi sono racchiusi nei costruttori Boolean
, Number
e String
diventano rispettivamente oggetti. L'operatore instanceof
funziona solo per gli oggetti (motivo per cui restituisce false
per i valori primitivi):
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
Come puoi vedere sia typeof
che instanceof
sono insufficienti per verificare se un valore è un valore booleano, un numero o una stringa - typeof
funziona solo per booleani, numeri e stringhe primitivi; e instanceof
non funziona per booleani, numeri e stringhe primitivi.
Fortunatamente esiste una soluzione semplice a questo problema. L'implementazione predefinita di toString
(ovvero come nativamente definita su Object.prototype.toString
) restituisce la proprietà [[Class]]
interna di entrambi valori e oggetti primitivi:
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 proprietà [[Class]]
interna di un valore è molto più utile del typeof
il valore. Possiamo usare Object.prototype.toString
per creare la nostra versione (più utile) dell'operatore typeof
come segue:
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
Spero che questo articolo abbia aiutato. Per saperne di più sulle differenze tra primitivi e oggetti avvolti leggi il seguente post sul blog: La vita segreta dei JavaScript & nbsp; Primitivi
Puoi usare la proprietà di costruzione:
'foo'.constructor == String // returns true
true.constructor == Boolean // returns true
typeof(text) === 'string' || text instanceof String;
puoi usarlo, funzionerà per entrambi i casi come
var text = " foo " ;;
// typeof funzioneràString text = new String (" foo ");
// instanceof funzionerà
Credo di aver trovato una soluzione praticabile:
Object.getPrototypeOf('test') === String.prototype //true
Object.getPrototypeOf(1) === String.prototype //false
Questo è definito nella specifica ECMAScript Sezione 7.3.19 Passaggio 3 : Se Type (O) non è Object, restituisce false.
In altre parole, se Obj
in Obj istanza di Callable
non è un oggetto, istanza di
passerà in cortocircuito a false
direttamente.
https://www.npmjs.com/package/typeof
Restituisce una rappresentazione in forma di stringa di instanceof
(il nome del costruttore)
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"
Per me la confusione causata da
"str".__proto__ // #1
=> String
Quindi " str " istanceof String
dovrebbe restituire true
perché come funziona istanceof come di seguito:
"str".__proto__ == String.prototype // #2
=> true
I risultati dell'espressione # 1 e # 2 sono in conflitto tra loro, quindi dovrebbe essercene uno sbagliato.
# 1 è sbagliato
Ho capito che è causato dalla __proto__
non è una proprietà standard, quindi usa quella standard: Object.getPrototypeOf
Object.getPrototypeOf("str") // #3
=> TypeError: Object.getPrototypeOf called on non-object
Ora non c'è confusione tra l'espressione # 2 e #3
O puoi semplicemente fare la tua funzione in questo modo:
function isInstanceOf(obj, clazz){
return (obj instanceof eval("("+clazz+")")) || (typeof obj == clazz.toLowerCase());
};
utilizzo:
isInstanceOf('','String');
isInstanceOf(new String(), 'String');
Entrambi dovrebbero restituire true.