Quelle est la différence entre typeof et instanceof et quand doit-on être utilisé par rapport à l'autre?
-
23-08-2019 - |
Question
Dans mon cas particulier:
callback instanceof Function
ou
typeof callback == "function"
est-il important même, quelle est la différence?
Ressource supplémentaire:
JavaScript Jardin typeof vs instanceof
La solution
Utilisez instanceof
pour les types personnalisés:
var ClassFirst = function () {};
var ClassSecond = function () {};
var instance = new ClassFirst();
typeof instance; // object
typeof instance == 'ClassFirst'; // false
instance instanceof Object; // true
instance instanceof ClassFirst; // true
instance instanceof ClassSecond; // false
Utilisation typeof
pour de simples types intégrés:
'example string' instanceof String; // false
typeof 'example string' == 'string'; // true
'example string' instanceof Object; // false
typeof 'example string' == 'object'; // false
true instanceof Boolean; // false
typeof true == 'boolean'; // true
99.99 instanceof Number; // false
typeof 99.99 == 'number'; // true
function() {} instanceof Function; // true
typeof function() {} == 'function'; // true
Utilisation instanceof
pour complexe construit dans les types:
/regularexpression/ instanceof RegExp; // true
typeof /regularexpression/; // object
[] instanceof Array; // true
typeof []; //object
{} instanceof Object; // true
typeof {}; // object
Et le dernier est un peu délicat:
typeof null; // object
Autres conseils
Les deux sont similaires dans la fonctionnalité, car ils ont tous deux des informations de type de retour, mais je préfère personnellement instanceof
parce qu'il est à comparer les types réels plutôt que des chaînes. Comparaison de type est moins sujette à l'erreur humaine, et il est techniquement plus rapide car il est la comparaison des pointeurs dans la mémoire plutôt que de faire des comparaisons entières de chaîne.
Une bonne raison d'utiliser typeof est si la variable peut être défini.
alert(typeof undefinedVariable); // alerts the string "undefined"
alert(undefinedVariable instanceof Object); // throws an exception
Une bonne raison d'utiliser est instanceof si la variable peut être nulle.
var myNullVar = null;
alert(typeof myNullVar ); // alerts the string "object"
alert(myNullVar instanceof Object); // alerts "false"
Alors, vraiment, à mon avis, il dépend de quel type de données possible que vous vérifiez.
Pour rendre les choses claires, vous devez savoir deux faits:
- instanceof opérateur teste si le propriété prototype d'un constructeur apparaît partout dans la chaîne de prototypes d'un objet. Dans la plupart des cas, cela signifie que l'objet était créé en utilisant ce constructeur ou de son descendant. Mais aussi le prototype peut être défini explicitement par la méthode
Object.setPrototypeOf()
(ECMAScript 2015) ou par la propriété__proto__
(anciens navigateurs, dépréciées). Modification du prototype d'un objet est cependant pas recommandée en raison de problèmes de performance.
Ainsi est instanceof applicable uniquement aux objets. Dans la plupart des cas, vous n'utilisez pas des constructeurs pour créer des chaînes ou des nombres. Vous pouvez. Mais vous faites presque jamais.
En outre instanceof ne peut pas vérifier exactement quel constructeur a été utilisé pour créer l'objet, mais retourne vrai, même si l'objet est dérivé de la classe qui en cours de vérification. Dans la plupart des cas est le comportement souhaité, mais il est parfois pas. Donc, vous devez garder cet esprit.
Un autre problème est que les différents champs d'application ont différents environnements d'exécution. Cela signifie qu'ils ont des built-ins (différents objets global, les différents constructeurs, etc.). Cela peut entraîner des résultats inattendus.
Par exemple, [] instanceof window.frames[0].Array
retournera false
, parce que Array.prototype !== window.frames[0].Array
et les tableaux héritent de l'ancienne.
En outre, il ne peut pas être utilisé sur la valeur non définie, car il ne pas un prototype.
- typeof opérateur teste si la valeur appartiennent à l'un des six types de base : " nombre ", « string », " boolean ", " objet ", " fonction " ou " undefined ". Lorsque la chaîne « objet » appartiennent tous les objets (à l'exception des fonctions, qui sont des objets, mais qui ont sa propre valeur dans l'opérateur typeof), et aussi la valeur « null » et les tableaux (pour « null » c'est un bug, mais ce bug est si vieux , il est devenu une norme). Il ne repose pas sur les constructeurs et peut être utilisé même si la valeur est définie. Mais il est ne donne pas de détails sur les objets. Donc, si vous en avez besoin, allez à instanceof.
Maintenant, nous allons parler d'une chose délicate. Que faire si vous utilisez constructeur pour créer un type primitif?
let num = new Number(5);
console.log(num instanceof Number); // print true
console.log(typeof num); // print object
num++; //num is object right now but still can be handled as number
//and after that:
console.log(num instanceof Number); // print false
console.log(typeof num); // print number
On dirait que la magie. Mais ce n'est pas. Il est ce qu'on appelle la boxe (valeur primitive d'emballage par objet) et unboxing (extraction de la valeur primitive enveloppé de l'objet). Ce type de code semble être « un peu » fragile. Bien sûr, vous pouvez simplement éviter de créer type primitif avec les constructeurs. Mais il y a une autre situation possible, quand la boxe peut vous frapper. Lorsque vous utilisez Function.call () ou Function.apply () sur un type primitif.
function test(){
console.log(typeof this);
}
test.apply(5);
Pour éviter cela, vous pouvez utiliser le mode strict:
function test(){
'use strict';
console.log(typeof this);
}
test.apply(5);
màj: Depuis 2015 ECMAScript, il y a un type plus appelé symbole, qui a son propre typeof == "symbole" .
console.log(typeof Symbol());
// expected output: "symbol"
J'ai découvert un comportement vraiment intéressant (lire comme « horrible ») dans Safari 5 et Internet Explorer 9. J'utilisais cela avec beaucoup de succès dans Chrome et Firefox.
if (typeof this === 'string') {
doStuffWith(this);
}
Puis-je tester dans IE9, et il ne fonctionne pas du tout. Grosse surprise. Mais dans Safari, il est intermittent! Je commence le débogage, et je trouve que Internet Explorer est toujours retour false
. Mais la chose la plus étrange est que Safari semble faire une sorte d'optimisation dans sa machine virtuelle JavaScript où il est true
premier temps, mais false
à chaque fois que vous frappez reload!
Mon cerveau a explosé presque.
Alors maintenant, je suis installé sur ce point:
if (this instanceof String || typeof this === 'string')
doStuffWith(this.toString());
}
Et maintenant tout fonctionne très bien. Notez que vous pouvez appeler "a string".toString()
et renvoie juste une copie de la chaîne, i.e..
"a string".toString() === new String("a string").toString(); // true
Je vais utiliser les deux à partir de maintenant.
instanceof
fonctionne également lorsque callback
est un sous-type de Function
, je pense
D'autres importantes différences pratiques:
// Boolean
var str3 = true ;
alert(str3);
alert(str3 instanceof Boolean); // false: expect true
alert(typeof str3 == "boolean" ); // true
// Number
var str4 = 100 ;
alert(str4);
alert(str4 instanceof Number); // false: expect true
alert(typeof str4 == "number" ); // true
instanceof
en Javascript peut être squameuse - Je crois que les cadres principaux tentent d'éviter son utilisation. Différentes fenêtres est l'une des façons dont il peut briser -. Je crois que les hiérarchies de classe peuvent confondre et
Il y a de meilleures façons pour vérifier si un objet est un certain type intégré (ce qui est généralement ce que vous voulez). Créer des fonctions d'utilité et de les utiliser:
function isFunction(obj) {
return typeof(obj) == "function";
}
function isArray(obj) {
return typeof(obj) == "object"
&& typeof(obj.length) == "number"
&& isFunction(obj.push);
}
Et ainsi de suite.
instanceof
ne fonctionnera pas pour les primitives, par exemple "foo" instanceof String
retournera false
alors typeof "foo" == "string"
retournera true
.
autre typeof
main ne sera probablement pas faire ce que vous voulez, quand il s'agit d'objets personnalisés (ou classes, tout ce que vous voulez les appeler). Par exemple:
function Dog() {}
var obj = new Dog;
typeof obj == 'Dog' // false, typeof obj is actually "object"
obj instanceof Dog // true, what we want in this case
Il se trouve que les fonctions sont les deux primitives « fonction » et les instances de « fonction », qui est un peu étrange étant donné que cela ne fonctionne pas comme pour les autres types primitifs, par exemple.
(typeof function(){} == 'function') == (function(){} instanceof Function)
(typeof 'foo' == 'string') != ('foo' instanceof String)
Je recommande d'utiliser le callback.isFunction()
de prototype.
Ils ont compris la différence et vous pouvez compter sur leur raison.
Je suppose que d'autres cadres JS ont des choses aussi.
instanceOf
ne fonctionnerait pas sur les fonctions définies dans d'autres fenêtres, je crois.
Leur fonction est différent de votre window.Function
.
Lors de la vérification d'une fonction, il faut toujours utiliser typeof
.
Voici la différence:
var f = Object.create(Function);
console.log(f instanceof Function); //=> true
console.log(typeof f === 'function'); //=> false
f(); // throws TypeError: f is not a function
Ceci est la raison pour laquelle il ne faut jamais utiliser instanceof
pour vérifier une fonction.
différence pratique significative:
var str = 'hello word';
str instanceof String // false
typeof str === 'string' // true
Ne me demandez pas pourquoi.
Performance
typeof
est plus rapide que instanceof
dans les situations où les deux sont applicables.
En fonction de votre moteur, la différence de performance en faveur de typeof
pourrait être autour de 20% . ( Votre kilométrage peut varier )
Voici un test de référence pour Array
:
var subject = new Array();
var iterations = 10000000;
var goBenchmark = function(callback, iterations) {
var start = Date.now();
for (i=0; i < iterations; i++) { var foo = callback(); }
var end = Date.now();
var seconds = parseFloat((end-start)/1000).toFixed(2);
console.log(callback.name+" took: "+ seconds +" seconds.");
return seconds;
}
// Testing instanceof
var iot = goBenchmark(function instanceofTest(){
(subject instanceof Array);
}, iterations);
// Testing typeof
var tot = goBenchmark(function typeofTest(){
(typeof subject == "object");
}, iterations);
var r = new Array(iot,tot).sort();
console.log("Performance ratio is: "+ parseFloat(r[1]/r[0]).toFixed(3));
Résultat
instanceofTest took: 9.98 seconds.
typeofTest took: 8.33 seconds.
Performance ratio is: 1.198
Ceci est juste des connaissances complémentaires à toutes les autres explications ici -. Je suis pas qui suggère d'utiliser .constructor
partout
TL; DR: Dans les situations où typeof
est pas une option, et quand vous savez que vous ne se soucient pas de la chaîne prototype , Object.prototype.constructor
peut être une solution viable ou encore meilleure alternative que instanceof
:
x instanceof Y
x.constructor === Y
Il a été dans la norme depuis 1.1, donc pas de soucis sur la compatibilité ascendante.
Muhammad Umer brièvement parlé dans un commentaire quelque part ici aussi. Il fonctionne sur tout avec un prototype - donc pas tout null
ou undefined
:
// (null).constructor; // TypeError: null has no properties
// (undefined).constructor; // TypeError: undefined has no properties
(1).constructor; // function Number
''.constructor; // function String
([]).constructor; // function Array
(new Uint8Array(0)).constructor; // function Uint8Array
false.constructor; // function Boolean()
true.constructor; // function Boolean()
(Symbol('foo')).constructor; // function Symbol()
// Symbols work, just remember that this is not an actual constructor:
// new Symbol('foo'); //TypeError: Symbol is not a constructor
Array.prototype === window.frames.Array; // false
Array.constructor === window.frames.Array.constructor; // true
En outre, selon votre cas d'utilisation, il peut être beaucoup plus vite que instanceof
(la raison étant probable qu'il ne dispose pas de vérifier l'ensemble de la chaîne de prototype). Dans mon cas je besoin d'un moyen rapide de vérifier si une valeur est un tableau typé:
function isTypedArrayConstructor(obj) {
switch (obj && obj.constructor){
case Uint8Array:
case Float32Array:
case Uint16Array:
case Uint32Array:
case Int32Array:
case Float64Array:
case Int8Array:
case Uint8ClampedArray:
case Int16Array:
return true;
default:
return false;
}
}
function isTypedArrayInstanceOf(obj) {
return obj instanceof Uint8Array ||
obj instanceof Float32Array ||
obj instanceof Uint16Array ||
obj instanceof Uint32Array ||
obj instanceof Int32Array ||
obj instanceof Float64Array ||
obj instanceof Int8Array ||
obj instanceof Uint8ClampedArray ||
obj instanceof Int16Array;
}
https://run.perf.zone/view/isTypedArray -constructor-vs-instanceof-1519140393812
Et les résultats:
Chrome 64.0.3282.167 (64-bit, Windows)
Firefox 59.0b10 (64 bits, Windows)
Hors curiousity, je l'ai fait une référence de jouet rapide contre typeof
; étonnamment, il ne fonctionne pas bien pire, et il semble même un peu plus rapide dans Chrome:
let s = 0,
n = 0;
function typeofSwitch(t) {
switch (typeof t) {
case "string":
return ++s;
case "number":
return ++n;
default:
return 0;
}
}
// note: no test for null or undefined here
function constructorSwitch(t) {
switch (t.constructor) {
case String:
return ++s;
case Number:
return ++n;
default:
return 0;
}
}
let vals = [];
for (let i = 0; i < 1000000; i++) {
vals.push(Math.random() <= 0.5 ? 0 : 'A');
}
https://run.perf.zone / view / typeof-vs-constructeur-string ou numéro-1519142623570
NOTE: L'ordre dans lequel les fonctions sont répertoriées Commute entre les images
Chrome 64.0.3282.167 (64-bit, Windows)
Firefox 59.0b10 (64 bits, Windows)
NOTE: L'ordre dans lequel les fonctions sont répertoriées Commute entre les images
Utilisez instanceof parce que si vous modifiez le nom de la classe, vous obtiendrez une erreur de compilation.
var newObj = new Object;//instance of Object
var newProp = "I'm xgqfrms!" //define property
var newFunc = function(name){//define function
var hello ="hello, "+ name +"!";
return hello;
}
newObj.info = newProp;// add property
newObj.func = newFunc;// add function
console.log(newObj.info);// call function
// I'm xgqfrms!
console.log(newObj.func("ET"));// call function
// hello, ET!
console.log(newObj instanceof Object);
//true
console.log(typeof(newObj));
//"object"
Issu d'une éducation stricte OO Je vais pour
callback instanceof Function
Les chaînes sont sujettes à soit mon orthographe terrible ou d'autres fautes de frappe. De plus, je pense qu'il lit mieux.
Malgré instanceof peut être un peu plus rapide, puis typeof , je préfère deuxième à cause d'une telle magie possible:
function Class() {};
Class.prototype = Function;
var funcWannaBe = new Class;
console.log(funcWannaBe instanceof Function); //true
console.log(typeof funcWannaBe === "function"); //false
funcWannaBe(); //Uncaught TypeError: funcWannaBe is not a function
Un autre cas est que vous ne pouvez collationner avec instanceof
- il retourne vrai ou faux. Avec typeof
vous pouvez obtenir le type de condition quelque chose
avec des performances à l'esprit, vous feriez mieux d'utiliser typeof avec un matériel typique, si vous créez un script avec une boucle de 10 millions d'itérations l'instruction: typeof str == 'string' prendra 9ms tandis que 'string' instanceof chaîne prendra 19ms
Bien sûr, il importe ........!
Marchons avec cette grâce examples.In notre exemple, nous allons déclarer la fonction de deux manières différentes.
Nous allons utiliser deux function declaration
et Fonction Constructor . Nous allons se comment typeof
et instanceof
se comporte dans ces deux scénarios différents.
Créer une fonction à l'aide déclaration de fonction:
function MyFunc(){ }
typeof Myfunc == 'function' // true
MyFunc instanceof Function // false
Explication possible pour un tel résultat différent est, comme nous l'avons fait une déclaration de fonction, typeof
peut comprendre qu'il est un function.Because typeof
vérifie si l'expression ou non qui est typeof opération sur, dans notre cas MyFunc
mis en œuvre Appel Méthode ou non . Si elle met en œuvre Call
méthode est un function.Otherwise pas .pour contrôle de clarification spécification ECMAScript pour typeof .
fonction créée à l'aide de la fonction constructeur:
var MyFunc2 = new Function('a','b','return a+b') // A function constructor is used
typeof MyFunc2 == 'function' // true
MyFunc2 instanceof Function // true
ici typeof
affirme que MyFunc2
est une fonction aussi bien que la instanceof
operator.We savent déjà typeof
vérifier si MyFunc2
mis en œuvre Call
méthode ou not.As MyFunc2
est une fonction et il met en oeuvre call
méthode , voilà comment typeof
sait que c'est un function.On d'autre part, nous avons utilisé function constructor
pour créer MyFunc2
, il devient une instance de Function constructor
.That's pourquoi instanceof
Déclare aussi true
.
Quoi de plus sûr à utiliser?
Comme on peut le voir dans les deux cas typeof
opérateur peut affirmer avec succès que nous avons affaire à une fonction ici, il est plus sûr que instanceof
. instanceof
échouera en cas de function declaration
parce que function declarations
ne sont pas une instance de Function constructor
.
Les meilleures pratiques:
Gary Rafferty suggéré, la meilleure façon devrait utiliser les deux typeof et instanceof ensemble.
function isFunction(functionItem) {
return typeof(functionItem) == 'function' || functionItem instanceof Function;
}
isFunction(MyFunc) // invoke it by passing our test function as parameter