Qual é a diferença entre typeof e instanceof e quando um deve ser usado versus o outro?

No meu caso particular:

callback instanceof Function 

ou

 typeof callback == "function" 

isso importa mesmo, qual a diferença?

Recurso Adicional:

Tipo de jardim JavaScript vs instanceof

Use instanceof para tipos personalizados:

 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 

Use typeof para tipos incorporados simples:

 '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 

Use instanceof para tipos incorporados complexos:

 /regularexpression/ instanceof RegExp; // true typeof /regularexpression/; // object [] instanceof Array; // true typeof []; //object {} instanceof Object; // true typeof {}; // object 

E o último é um pouco complicado:

 typeof null; // object 

Ambos são semelhantes em funcionalidade porque ambos retornam informações de tipo, no entanto eu pessoalmente prefiro instanceof porque é comparar tipos reais em vez de strings. A comparação de tipos é menos propensa a erros humanos, e é tecnicamente mais rápida, já que está comparando pointers na memory, em vez de fazer comparações inteiras de strings.

Uma boa razão para usar typeof é se a variável pode ser indefinida.

 alert(typeof undefinedVariable); // alerts the string "undefined" alert(undefinedVariable instanceof Object); // throws an exception 

Um bom motivo para usar instanceof é se a variável pode ser nula.

 var myNullVar = null; alert(typeof myNullVar ); // alerts the string "object" alert(myNullVar instanceof Object); // alerts "false" 

Então, na verdade, na minha opinião, isso dependeria do tipo de dados possíveis que você está verificando.

Para esclarecer as coisas, você precisa conhecer dois fatos:

  1. O operador instanceof testa se a propriedade prototype de um construtor aparece em qualquer lugar na cadeia de protótipos de um object. Na maioria dos casos, isso significa que o object foi criado usando esse construtor ou um de seus descendentes. Mas também o protótipo pode ser definido explicitamente pelo método Object.setPrototypeOf() (ECMAScript 2015) ou pela propriedade __proto__ (navegadores antigos, obsoletos). Alterar o protótipo de um object não é recomendado, devido a problemas de desempenho.

Assim, a instância é aplicável apenas a objects. Na maioria dos casos, você não está usando construtores para criar cadeias ou números. Você pode. Mas você quase nunca faz.

Também instanceof não pode verificar, exatamente qual construtor foi usado para criar o object, mas retornará true, mesmo que o object seja derivado da class que está sendo verificada. Na maioria dos casos, esse é o comportamento desejado, mas às vezes não é. Então você precisa manter essa mente.

Outro problema é que diferentes escopos possuem diferentes ambientes de execução. Isso significa que eles têm diferentes built-ins (diferentes objects globais, diferentes construtores, etc.). Isso pode resultar em resultados inesperados.

Por exemplo, [] instanceof window.frames[0].Array retornará false , porque Array.prototype !== window.frames[0].Array e matrizes herdam do primeiro.
Além disso, ele não pode ser usado em um valor indefinido, porque não possui um protótipo.

  1. O operador typeof testa se o valor pertence a um dos seis tipos básicos : ” number “, ” string “, ” boolean “, ” object “, ” function ” ou ” undefined “. Onde a string “object” pertence a todos os objects (exceto funções, que são objects, mas tem seu próprio valor no operador typeof), e também valor “nulo” e arrays (para “null” é um bug, mas esse bug é tão antigo , então se tornou um padrão). Não depende de construtores e pode ser usado mesmo se o valor for indefinido. Mas não dá detalhes sobre objects. Então, se você precisar, vá para instanceof.

Agora vamos falar sobre uma coisa complicada. E se você usar o construtor para criar um tipo primitivo?

 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 

Parece mágica. Mas não é. É o chamado boxe (envolvendo valor primitivo por object) e unboxing (extraindo o valor primitivo do object). Esse tipo de código parece ser “um pouco” frágil. Claro que você pode evitar a criação de tipos primitivos com construtores. Mas há outra situação possível, quando o boxe pode bater em você. Quando você usa Function.call () ou Function.apply () em um tipo primitivo.

 function test(){ console.log(typeof this); } test.apply(5); 

Para evitar isso, você pode usar o modo estrito:

 function test(){ 'use strict'; console.log(typeof this); } test.apply(5); 

upd: Desde o ECMAScript 2015, existe mais um tipo chamado Symbol, que possui seu próprio typeof == “symbol” .

 console.log(typeof Symbol()); // expected output: "symbol" 

Você pode ler sobre isso no MDN: ( Symbol , typeof ).

Eu descobri um comportamento realmente interessante (leia como “horrível”) no Safari 5 e no Internet Explorer 9. Eu estava usando isso com grande sucesso no Chrome e no Firefox.

 if (typeof this === 'string') { doStuffWith(this); } 

Então eu testo no IE9, e não funciona de jeito nenhum. Grande surpresa. Mas no Safari, é intermitente! Por isso, começo a depurar e descubro que o Internet Explorer está sempre retornando false . Mas o mais estranho é que o Safari parece estar fazendo algum tipo de otimização em sua VM JavaScript, onde é true na primeira vez, mas false toda vez que você acerta o recarregamento!

Meu cérebro quase explodiu.

Então agora eu resolvi isso:

 if (this instanceof String || typeof this === 'string') doStuffWith(this.toString()); } 

E agora tudo funciona muito bem. Note que você pode chamar "a string".toString() e apenas retorna uma cópia da string, ie

 "a string".toString() === new String("a string").toString(); // true 

Então eu vou usar os dois a partir de agora.

instanceof também funciona quando callback é um subtipo de Function , acho

Outras diferenças práticas significativas:

 // 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 de Javascript pode ser esquisito – acredito que os principais frameworks tentam evitar seu uso. Janelas diferentes são uma das maneiras pelas quais ele pode quebrar – acredito que as hierarquias de class também podem confundi-lo.

Existem maneiras melhores de testar se um object é um determinado tipo interno (que geralmente é o que você deseja). Crie funções utilitárias e use-as:

 function isFunction(obj) { return typeof(obj) == "function"; } function isArray(obj) { return typeof(obj) == "object" && typeof(obj.length) == "number" && isFunction(obj.push); } 

E assim por diante.

instanceof não funcionará para primitivos, por exemplo, "foo" instanceof String retornará false enquanto typeof "foo" == "string" retornará true .

Por outro lado, typeof provavelmente não fará o que você quer quando se trata de objects personalizados (ou classs, o que você quiser chamá-los). Por exemplo:

 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 

Acontece que as funções são primitivas de ‘function’ e instâncias de ‘Função’, o que é um pouco estranho, já que não funciona assim para outros tipos primitivos, por exemplo.

 (typeof function(){} == 'function') == (function(){} instanceof Function) 

mas

 (typeof 'foo' == 'string') != ('foo' instanceof String) 

Eu recomendaria usar o callback.isFunction() do protótipo.

Eles descobriram a diferença e você pode contar com a razão deles.

Eu acho que outros frameworks JS também têm essas coisas.

instanceOf não funcionaria em funções definidas em outras janelas, acredito. Sua function é diferente da sua window.Function .

Ao verificar uma function, deve-se sempre usar typeof .

Aqui está a diferença:

 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 

É por isso que nunca se deve usar instanceof para verificar uma function.

Diferença prática significativa:

 var str = 'hello word'; str instanceof String // false typeof str === 'string' // true 

Não me pergunte por quê.

atuação

typeof é mais rápido que instanceof em situações em que ambos são aplicáveis.

Dependendo do seu motor, a diferença de desempenho em favor do typeof pode ser em torno de 20% . ( Sua milhagem pode variar )

Aqui está um teste de benchmark para o 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)); 

Resultado

 instanceofTest took: 9.98 seconds. typeofTest took: 8.33 seconds. Performance ratio is: 1.198 

Este é apenas um conhecimento complementar a todas as outras explicações aqui – não estou sugerindo usar o .constructor todos os lugares.

TL; DR: Em situações em que typeof não é uma opção, e quando você sabe que não se importa com a cadeia de protótipos , Object.prototype.constructor pode ser uma alternativa viável ou até melhor do que a instanceof :

 x instanceof Y x.constructor === Y 

Ele está no padrão desde 1.1, então não se preocupe com a compatibilidade com versões anteriores.

Muhammad Umer mencionou brevemente isso em um comentário em algum lugar aqui também. Ele funciona em tudo com um protótipo – então tudo não é 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 

Além disso, dependendo do seu caso de uso, pode ser muito mais rápido do que o instanceof (a razão provável é que ele não precisa verificar toda a cadeia de protótipos). No meu caso, eu precisava de uma maneira rápida de verificar se um valor é um array typescript:

 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

E os resultados:

Chrome 64.0.3282.167 (64 bits, Windows)

Typed Array instanceof vs constructor - 1.5x mais rápido no Chrome 64.0.3282.167 (64 bits, Windows)

Firefox 59.0b10 (64 bits, Windows)

Typed Array instanceof vs constructor - 30x mais rápido no Firefox 59.0b10 (64 bits, Windows)

Por curiosidade, fiz um rápido benchmark contra o typeof ; Surpreendentemente, o desempenho não é muito pior e parece até um pouco mais rápido no 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-1519142623570

NOTA: Ordem em que as funções estão listadas opções entre as imagens!

Chrome 64.0.3282.167 (64 bits, Windows)

String / Number typeof vs construtor - 1,26x mais rápido no Chrome 64.0.3282.167 (64 bits, Windows)

Firefox 59.0b10 (64 bits, Windows)

NOTA: Ordem em que as funções estão listadas opções entre as imagens!

String / Number typeof vs construtor - 0.78x mais lento no Firefox 59.0b10 (64 bits, Windows)

Use instanceof porque se você alterar o nome da class, receberá um erro do compilador.

 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" 

Vindo de uma educação estrita OO eu iria para

 callback instanceof Function 

Cordas são propensas a minha ortografia horrível ou outros erros de digitação. Além disso, sinto que lê melhor.

Apesar do exemplo poder ser um pouco mais rápido que o typeof , eu prefiro o segundo por causa de uma mágica possível:

 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 

Um caso a mais é que você só pode agrupar com instanceof – ele retorna true ou false. Com typeof você pode obter o tipo de algo fornecido

com o desempenho em mente, é melhor usar typeof com um hardware típico, se você criar um script com um loop de 10 milhões de iterações, a instrução: typeof str == ‘string’ levará 9ms enquanto ‘string’ instanceof String levará 19ms

Claro que importa ……..!

Vamos percorrer isso com exemplos. Em nosso exemplo, declararemos a function de duas maneiras diferentes.

Nós estaremos usando function declaration e construtor de function . Veremos como typeof e instanceof se comportam nesses dois cenários diferentes.

Criar function usando declaração de function:

 function MyFunc(){ } typeof Myfunc == 'function' // true MyFunc instanceof Function // false 

Explicação possível para tal resultado diferente é, como fizemos uma declaração de function, typeof pode entender que é uma function. typeof verifica se ou não a expressão na qual typeof é operação, no nosso caso MyFunc implementado Call Method ou não . Se ele implementa o método de Call é uma function.Caso contrário, não. Para esclarecimento verificar especificação ecmascript para typeof .

Criar function usando o construtor de function:

 var MyFunc2 = new Function('a','b','return a+b') // A function constructor is used typeof MyFunc2 == 'function' // true MyFunc2 instanceof Function // true 

Aqui typeof afirma que MyFunc2 é uma function, bem como o operador instanceof Já sabemos o typeof verificação se MyFunc2 implementou o método de Call ou não. Como MyFunc2 é uma function e implementa call método de call , é assim que typeof sabe que é uma function. Por outro lado, usamos o function constructor para criar MyFunc2 , ele se torna uma instância do Function constructor de Function constructor . É por isso que instanceof também resolve para true .

O que é mais seguro usar?

Como podemos ver em ambos os casos, o operador typeof pode afirmar com sucesso que estamos lidando com uma function aqui, é mais seguro que instanceof . instanceof falhará no caso da function declaration de function declaration porque function declarations não são uma instância do Function constructor .

Melhor pratica :

Como Gary Rafferty sugeriu, o melhor caminho deveria ser usar ambos typeof e instanceof juntos.

  function isFunction(functionItem) { return typeof(functionItem) == 'function' || functionItem instanceof Function; } isFunction(MyFunc) // invoke it by passing our test function as parameter