Dans mon cas particulier:
callback instanceof Function
ou
typeof callback == "function"
est-ce même important, quelle est la différence?
Ressource supplémentaire:
JavaScript-Garden typeof vs instanceof
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
typeof
pour les types simples 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
instanceof
pour les types intégrés complexes:/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
Les deux fonctionnalités sont similaires car elles renvoient toutes les deux des informations de type. Toutefois, je préfère personnellement instanceof
car il compare les types réels plutôt que les chaînes. La comparaison de types est moins sujette aux erreurs humaines et techniquement plus rapide, car elle compare des pointeurs en mémoire plutôt que des comparaisons de chaînes entières.
Une bonne raison d'utiliser typeof est si la variable peut être indéfinie.
alert(typeof undefinedVariable); // alerts the string "undefined"
alert(undefinedVariable instanceof Object); // throws an exception
Une bonne raison d'utiliser instanceof est si la variable peut être nulle.
var myNullVar = null;
alert(typeof myNullVar ); // alerts the string "object"
alert(myNullVar instanceof Object); // alerts "false"
Donc, à mon avis, cela dépend du type de données possibles que vous vérifiez.
Pour clarifier les choses, vous devez connaître deux faits:
Object.setPrototypeOf()
(ECMAScript 2015) ou par la propriété __proto__
(anciens navigateurs, obsolète). La modification du prototype d'un objet n'est toutefois pas recommandée en raison de problèmes de performances.Ainsi, instanceof n'est applicable qu'aux objets. Dans la plupart des cas, vous n'utilisez pas de constructeur pour créer des chaînes ou des nombres. Vous pouvez. Mais tu ne le fais presque jamais.
De plus, instanceof ne peut pas vérifier exactement quel constructeur a été utilisé pour créer l'objet, mais retournera true, même si l'objet est dérivé de la classe en cours de vérification. Dans la plupart des cas, c'est le comportement souhaité, mais parfois ce n'est pas le cas. Donc, vous devez garder cet esprit.
Un autre problème est que différentes portées ont différents environnements d'exécution. Cela signifie qu'ils ont différents éléments intégrés (objets globaux différents, constructeurs différents, etc.). Cela peut entraîner des résultats inattendus.
Par exemple, [] instanceof window.frames[0].Array
renverra false
, car Array.prototype !== window.frames[0].Array
et les tableaux hériteront de l'ancien.
En outre, il ne peut pas être utilisé sur une valeur indéfinie, car il n’a pas de prototype.
Parlons maintenant 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 de la magie. Mais ce n'est pas. C'est ce qu'on appelle boxing (valeur primitive enveloppante par objet) et unboxing (extraction de la valeur primitive enveloppée d'objet). Ce genre de code semble être "un peu" fragile. Bien sûr, vous pouvez simplement éviter de créer un type primitif avec des constructeurs. Mais il y a une autre situation possible, lorsque 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);
upd: Depuis ECMAScript 2015, il existe un type supplémentaire appelé Symbol, qui a son propre typeof == "symbole ".
console.log(typeof Symbol());
// expected output: "symbol"
J'ai découvert un comportement vraiment intéressant (lu comme "horrible") dans Safari 5 et Internet Explorer 9. Je l'utilisais avec un grand succès dans Chrome et Firefox.
if (typeof this === 'string') {
doStuffWith(this);
}
Ensuite, je teste dans IE9, et cela ne fonctionne pas du tout. Grosse surprise. Mais dans Safari, c'est intermittent! Donc, je commence le débogage, et je trouve qu'Internet Explorer est toujours retournant false
. Mais le plus étrange, c’est que Safari semble faire une sorte d’optimisation dans son JavaScript VM où il s’agit de true
le d’abord temps, mais false
chaque fois que vous appuyez sur reload!
Mon cerveau a presque explosé.
Alors maintenant, j'ai décidé de ceci:
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 qu’il ne retourne qu’une copie de la chaîne, c.-à-d.
"a string".toString() === new String("a string").toString(); // true
Donc, je vais utiliser les deux à partir de maintenant.
instanceof
fonctionne également lorsque callback
est un sous-type de Function
, je pense
Autres différences pratiques significatives:
// 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 floconneux - je crois que les principaux cadres tentent d’éviter son utilisation. Différentes fenêtres sont l’un des moyens par lesquels elle peut casser - je pense que les hiérarchies de classes peuvent aussi la confondre.
Il existe de meilleurs moyens de tester si un objet est un certain type intégré (qui correspond généralement à ce que vous souhaitez). Créez des fonctions utilitaires et utilisez-les:
function isFunction(obj) {
return typeof(obj) == "function";
}
function isArray(obj) {
return typeof(obj) == "object"
&& typeof(obj.length) == "number"
&& isFunction(obj.Push);
}
Etc.
Je recommanderais d'utiliser le prototype de callback.isFunction()
.
Ils ont compris la différence et vous pouvez compter sur leur raison.
Je suppose que d'autres frameworks JS ont de telles choses aussi.
instanceOf
ne fonctionnerait pas avec les fonctions définies dans d'autres fenêtres, je crois. Leur fonction est différente de votre window.Function
.
Lorsque vous recherchez une fonction, vous devez 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
C'est pourquoi il ne faut jamais utiliser instanceof
pour rechercher une fonction.
instanceof
ne fonctionnera pas pour les primitives, par exemple "foo" instanceof String
retournera false
alors que typeof "foo" == "string"
retournera true
.
D'autre part, typeof
ne fera probablement pas ce que vous voulez lorsqu'il s'agit d'objets personnalisés (ou de classes, comme 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 à la fois des primitives de "fonction" et des instances de "Fonction", ce qui est un peu étrange dans la mesure où cela ne fonctionne pas comme cela pour d'autres types primitifs, par exemple.
(typeof function(){} == 'function') == (function(){} instanceof Function)
mais
(typeof 'foo' == 'string') != ('foo' instanceof String)
Performance
typeof
est plus rapide que instanceof
dans les cas où les deux sont applicables.
En fonction de votre moteur, la différence de performances en faveur de typeof
pourrait être d'environ 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
Différence pratique significative:
var str = 'hello Word';
str instanceof String // false
typeof str === 'string' // true
Ne me demande pas pourquoi.
Ceci est juste une connaissance complémentaire à toutes les autres explications ici - je suis pas suggère d'utiliser _.constructor
_ partout.
TL; DR: Dans les situations où typeof
n'est pas une option et lorsque vous savez que vous ne vous souciez pas de la chaîne de prototypes, Object.prototype.constructor
peut être une alternative viable, voire meilleure, que instanceof
:
_x instanceof Y
x.constructor === Y
_
Il est dans la norme depuis la 1.1, alors ne vous inquiétez pas de la compatibilité en amont.
Muhammad Umer a brièvement mentionné cela dans un commentaire quelque part ici aussi. Cela fonctionne sur tout avec un prototype - donc tout ne soit pas 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
_
De plus, selon votre cas d'utilisation, il peut être beaucoup plus rapide que instanceof
(la raison étant probablement qu'il n'est pas nécessaire de vérifier toute la chaîne de prototypes). Dans mon cas, j'avais 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 bits, Windows)
Firefox 59.0b10 (64 bits, Windows)
Par curiosité, j’ai fait un repère rapide sur les jouets contre typeof
; étonnamment, ses performances ne sont pas moins mauvaises et cela 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-constructor-string-or-number-15191426262357
REMARQUE: L'ordre dans lequel les fonctions sont répertoriées bascule entre les images!
Chrome 64.0.3282.167 (64 bits, Windows)
Firefox 59.0b10 (64 bits, Windows)
REMARQUE: L'ordre dans lequel les fonctions sont répertoriées bascule entre les images!
Utilisez instanceof parce que si vous modifiez le nom de la classe, vous obtiendrez une erreur du compilateur.
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"
Venant d'une éducation stricte OO, j'irais bien
callback instanceof Function
Les chaînes sont sujettes à mon terrible orthographe ou à d'autres fautes de frappe. De plus, je sens que ça se lit mieux.
Un autre cas est que vous ne pouvez assembler qu'avec instanceof
- il renvoie true ou false. Avec typeof
vous pouvez obtenir le type de fourni quelque chose
Bien sûr, cela compte ........!
Passons en revue avec des exemples. Dans notre exemple, nous allons déclarer une fonction de deux manières différentes.
Nous utiliserons à la fois function declaration
et - Constructeur de fonction. Nous allons voir comment typeof
et instanceof
se comporte dans ces deux scénarios différents.
Créer une fonction à l'aide de la déclaration de fonction:
_function MyFunc(){ }
typeof Myfunc == 'function' // true
MyFunc instanceof Function // false
_
L’explication possible de ce résultat différent est que, comme nous l’avons fait une déclaration de fonction, typeof
peut comprendre qu’il s’agit d’une fonction.Par ailleurs typeof
vérifie si oui ou non l'expression sur laquelle typeof est une opération, dans notre cas MyFunc
mis en œuvreméthode d'appelou pas . Si elle implémente Call
, il s’agit d’une fonction. Sinon, pas. Pour vérification spécification ecmascript pour typeof =.
Créer une fonction à l'aide du constructeur de la fonction:
_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 ainsi que instanceof
.We connaissez déjà typeof
, vérifiez si MyFunc2
implémenté Call
méthode ou non.As MyFunc2
est une fonction qui implémente _ LA MÉTHODE call
, voilà comment typeof
sait que c'est une fonction. D'autre part, nous avons utilisé function constructor
pour créer MyFunc2
, il devient une instance de Function constructor
. C'est pourquoi instanceof
prend également la forme true
.
Qu'est-ce qui est le plus sûr à utiliser?
Comme nous pouvons le constater dans les deux cas , l'opérateur typeof
peut affirmer avec succès qu'il s'agit d'une fonction, il est donc plus sûr que instanceof
. instanceof
échouera si function declaration
car function declarations
n'est pas un instance de Function constructor
.
Meilleure pratique:
Comme Gary Rafferty suggéré, le meilleur moyen consiste à utiliser à la fois typeof et instanceof.
_ function isFunction(functionItem) {
return typeof(functionItem) == 'function' || functionItem instanceof Function;
}
isFunction(MyFunc) // invoke it by passing our test function as parameter
_
Malgré instanceof est peut-être un peu plus rapide que typeof, je préfère le second en raison de cette 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
en gardant à l'esprit les performances, vous feriez mieux d'utiliser typeof avec un matériel classique. Si vous créez un script avec une boucle de 10 millions d'itérations, l'instruction: typeof str == 'chaîne' prendra 9 ms tandis que 'chaîne' instanceof Chaîne prendra 19 ms