web-dev-qa-db-fra.com

Quelle est la différence entre typeof et instanceof et quand faut-il utiliser l'un par rapport à l'autre?

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

355
farinspace

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 

Utilisez 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

Utilisez 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
485
Szymon Wygnański

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.

120
Soviut

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.

95
Kenneth J

Pour clarifier les choses, vous devez connaître deux faits:

  1. L'opérateur instanceof teste si la propriété prototype d'un constructeur apparaît n'importe où dans la chaîne de prototypes d'un objet. Dans la plupart des cas, cela signifie que l'objet a été créé à l'aide de ce constructeur ou de l'un de ses descendants. Mais prototype peut aussi être défini explicitement par la méthode 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.

  1. L'opérateur typeof vérifie si la valeur appartient à l'un des six types de base : " nombre ", " chaîne ", " booléen "," objet "," fonction "ou" non défini ". Où la chaîne "objet" appartient à tous les objets (à l'exception des fonctions, qui ont leur propre valeur dans l'opérateur typeof), ainsi qu'à la valeur "null" et aux tableaux (pour "null", il s'agit d'un bogue, mais celui-ci est si ancien , alors c'est devenu un standard). Il ne repose pas sur des constructeurs et peut être utilisé même si la valeur n'est pas définie. Mais cela ne donne aucun détail sur les objets. Donc si vous en avez besoin, allez à instanceof.

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"

Vous pouvez lire à ce sujet sur MDN: ( Symbol , typeof ).

27
Vladimir Liubimov

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.

14
Justin Force

instanceof fonctionne également lorsque callback est un sous-type de Function, je pense

7
newacct

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
7
Amjad Farajallah

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.

4
levik

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.

3
alamar

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.

3
vitaly-t

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)
3
Omnimike

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
2
Martin Peter

Différence pratique significative:

var str = 'hello Word';

str instanceof String   // false

typeof str === 'string' // true

Ne me demande pas pourquoi.

2
Barney

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)

Typed Array instanceof vs constructor - 1.5x faster in Chrome 64.0.3282.167 (64-bit, Windows)

Firefox 59.0b10 (64 bits, Windows)

Typed Array instanceof vs constructor - 30x faster in Firefox 59.0b10 (64-bit, 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)

String/Number typeof vs constructor - 1.26x faster in Chrome 64.0.3282.167 (64-bit, Windows)

Firefox 59.0b10 (64 bits, Windows)

REMARQUE: L'ordre dans lequel les fonctions sont répertoriées bascule entre les images!

String/Number typeof vs constructor - 0.78x slower in Firefox 59.0b10 (64-bit, Windows)

2
Job

Utilisez instanceof parce que si vous modifiez le nom de la classe, vous obtiendrez une erreur du compilateur.

1
Robert
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"
1
xgqfrms

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.

0
Keplerf1

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

0

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
_
0
AL-zami

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
0
Suprido

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

0
Khalid Rafik