node - typeof javascript
¿Cuál es la diferencia entre typeof y instanceof? (21)
En mi caso particular:
callback instanceof Function
o
typeof callback == "function"
¿Importa eso, cuál es la diferencia?
Recurso adicional:
JavaScript-Garden typeof vs instanceof
Utilice 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
Utilice typeof
para tipos integrados 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
Utilice instanceof
para los tipos construidos complejos:
/regularexpression/ instanceof RegExp; // true
typeof /regularexpression/; // object
[] instanceof Array; // true
typeof []; //object
{} instanceof Object; // true
typeof {}; // object
Y el último es un poco complicado:
typeof null; // object
A pesar de que instanceof puede ser un poco más rápido que typeof , prefiero el segundo debido a una posible magia:
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
Al verificar una función, siempre se debe usar typeof
.
Aquí está la diferencia:
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
Esta es la razón por la que uno nunca debe usar instanceof
para verificar una función.
Ambos son similares en funcionalidad porque ambos devuelven información de tipo, sin embargo yo personalmente prefiero instanceof
porque compara tipos reales en lugar de cadenas. La comparación de tipos es menos propensa al error humano, y es técnicamente más rápida, ya que está comparando los punteros en la memoria en lugar de hacer comparaciones de cadenas completas.
Descubrí un comportamiento realmente interesante (leído como "horrible") en Safari 5 e Internet Explorer 9. Lo estaba usando con gran éxito en Chrome y Firefox.
if (typeof this === ''string'') {
doStuffWith(this);
}
Entonces pruebo en IE9, y no funciona en absoluto. Gran sorpresa. Pero en Safari, ¡es intermitente! Así que empiezo a depurar y encuentro que Internet Explorer siempre devuelve false
. Pero lo más extraño es que Safari parece estar haciendo algún tipo de optimización en su máquina virtual JavaScript, donde es true
la primera vez, ¡pero es false
cada vez que pulsa recargar!
Mi cerebro casi explotó.
Así que ahora me he decidido por esto:
if (this instanceof String || typeof this === ''string'')
doStuffWith(this.toString());
}
Y ahora todo funciona muy bien. Tenga en cuenta que puede llamar a "a string".toString()
y simplemente devuelve una copia de la cadena, es decir,
"a string".toString() === new String("a string").toString(); // true
Así que voy a utilizar ambos a partir de ahora.
Diferencia práctica significativa:
var str = ''hello word'';
str instanceof String // false
typeof str === ''string'' // true
No me preguntes por qué.
Este es solo un conocimiento complementario de todas las otras explicaciones aquí. No estoy sugiriendo usar .constructor
todas partes.
TL; DR: en situaciones en las que typeof
no es una opción, y cuando sabe que no le importa la cadena del prototipo , Object.prototype.constructor
puede ser una alternativa viable o incluso mejor que la instanceof
:
x instanceof Y
x.constructor === Y
Ha estado en el estándar desde 1.1, por lo que no se preocupa por la compatibilidad con versiones anteriores.
Muhammad Umer mencionó brevemente esto en un comentario aquí también. Funciona en todo con un prototipo, por lo que todo no es null
ni 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
Además, dependiendo de su caso de uso, puede ser mucho más rápido que instanceof
(la razón más probable es que no tiene que verificar toda la cadena del prototipo). En mi caso, necesitaba una forma rápida de comprobar si un valor es una matriz escrita:
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
Y los resultados:
Chrome 64.0.3282.167 (64 bits, Windows)
Firefox 59.0b10 (64 bits, Windows)
Por curiosidad, hice un punto de referencia de juguete rápido contra typeof
; Sorprendentemente, no tiene un rendimiento mucho peor, y parece incluso un poco más rápido en 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: El orden en el que se enumeran las funciones cambia entre imágenes!
Chrome 64.0.3282.167 (64 bits, Windows)
Firefox 59.0b10 (64 bits, Windows)
NOTA: El orden en el que se enumeran las funciones cambia entre imágenes!
Otras diferencias prácticas 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
Para aclarar las cosas, necesita saber dos hechos:
- El operador instanceof comprueba si la propiedad prototipo de un constructor aparece en algún lugar de la cadena de prototipos de un objeto. En la mayoría de los casos, esto significa que el objeto se creó utilizando este constructor o uno de sus descendientes. Pero también el prototipo puede establecerse explícitamente por el método
Object.setPrototypeOf()
(ECMAScript 2015) o por la propiedad__proto__
(navegadores antiguos, obsoletos). Sin embargo, no se recomienda cambiar el prototipo de un objeto, debido a problemas de rendimiento.
Por lo tanto, instanceof solo es aplicable a objetos. En la mayoría de los casos, no estás utilizando constructores para crear cadenas o números. Usted puede. Pero casi nunca lo haces.
Además, instanceof no puede verificar, exactamente qué constructor se usó para crear el objeto, pero devolverá verdadero, incluso si el objeto se deriva de la clase que se verifica. En la mayoría de los casos, este es el comportamiento deseado, pero a veces no lo es. Así que necesitas mantener esa mente.
Otro problema es que los diferentes ámbitos tienen diferentes entornos de ejecución. Esto significa que tienen diferentes elementos incorporados (objeto global diferente, constructores diferentes, etc.). Esto puede dar lugar a resultados inesperados.
Por ejemplo, [] instanceof window.frames[0].Array
devolverá false
, porque Array.prototype !== window.frames[0].Array
y las matrices heredan de la anterior.
Además, no se puede utilizar en un valor indefinido, porque no tiene un prototipo.
- El operador typeof comprueba si el valor pertenece a uno de los seis tipos básicos : " número ", " cadena ", " booleano ", " objeto ", " función " o " indefinido ". Donde la cadena "objeto" pertenece a todos los objetos (excepto las funciones, que son objetos, pero tienen su propio valor en el tipo de operador), y también el valor "nulo" y las matrices (para "nulo" es un error, pero este error es tan antiguo , por lo que se ha convertido en un estándar). No depende de los constructores y puede usarse incluso si el valor no está definido. Pero no da ningún detalle sobre los objetos. Así que si lo necesitabas, ve a instanceof.
Ahora vamos a hablar de una cosa difícil. ¿Qué pasa si usas el constructor para crear un 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 magia. Pero no lo es. Se denomina boxeo (ajuste del valor primitivo por objeto) y desempaquetado (extracción del valor primitivo ajustado del objeto). Este tipo de código parece ser "un poco" frágil. Por supuesto, simplemente puede evitar la creación de tipos primitivos con constructores. Pero hay otra situación posible, cuando el boxeo puede golpearte. Cuando utiliza Function.call () o Function.apply () en un tipo primitivo.
function test(){
console.log(typeof this);
}
test.apply(5);
Para evitar esto puedes usar el modo estricto:
function test(){
''use strict'';
console.log(typeof this);
}
test.apply(5);
upd: Desde ECMAScript 2015, hay un tipo más llamado Símbolo, que tiene su propio tipo de == "símbolo" .
console.log(typeof Symbol());
// expected output: "symbol"
Recomendaría usar el callback.isFunction()
prototype.
Ellos han descubierto la diferencia y usted puede contar con su razón.
Supongo que otros frameworks JS también tienen esas cosas.
instanceOf
no funcionaría en funciones definidas en otras ventanas, creo. Su función es diferente a su window.Function
. window.Function
.
Un caso más es que solo puede cotejar con instanceof
: devuelve verdadero o falso. Con typeof
puedes obtener el tipo de algo proporcionado.
Una buena razón para usar typeof es si la variable puede no estar definida.
alert(typeof undefinedVariable); // alerts the string "undefined"
alert(undefinedVariable instanceof Object); // throws an exception
Una buena razón para usar instanceof es si la variable puede ser nula.
var myNullVar = null;
alert(typeof myNullVar ); // alerts the string "object"
alert(myNullVar instanceof Object); // alerts "false"
En realidad, en mi opinión, dependerá del tipo de datos posibles que esté verificando.
Use instanceof porque si cambia el nombre de la clase obtendrá un error del compilador.
Viniendo de una educación estricta OO iría para
callback instanceof Function
Las cadenas son propensas a mi horrible ortografía u otros errores tipográficos. Además siento que se lee mejor.
teniendo en cuenta el rendimiento, es mejor que uses typeof con un hardware típico, si creas un script con un bucle de 10 millones de iteraciones, la instrucción: typeof str == ''string'' tomará 9ms mientras que ''string'' instanceof String tomará 19ms
instanceof
de Javascript puede ser inestable. Creo que los principales marcos intentan evitar su uso. Diferentes ventanas es una de las formas en que se puede romper. Creo que las jerarquías de clase también pueden confundirlo.
Hay mejores formas de probar si un objeto es un determinado tipo incorporado (que generalmente es lo que usted quiere). Crea funciones de utilidad y úsalas:
function isFunction(obj) {
return typeof(obj) == "function";
}
function isArray(obj) {
return typeof(obj) == "object"
&& typeof(obj.length) == "number"
&& isFunction(obj.push);
}
Y así.
instanceof
no funcionará para primitivas, por ejemplo, "foo" instanceof String
devolverá false
mientras que typeof "foo" == "string"
devolverá true
.
Por otro lado, typeof
probablemente no hará lo que quieres cuando se trata de objetos personalizados (o clases, como quieras llamarlos). Por ejemplo:
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
Da la casualidad de que las funciones son tanto primitivas de ''función'' como instancias de ''Función'', lo cual es un tanto extraño dado que no funciona así para otros tipos primitivos, por ejemplo.
(typeof function(){} == ''function'') == (function(){} instanceof Function)
pero
(typeof ''foo'' == ''string'') != (''foo'' instanceof String)
instanceof
también funciona cuando la callback
es un subtipo de Function
, creo
Por supuesto que importa ........!
Analicemos esto con ejemplos. En nuestro ejemplo, declararemos la función de dos maneras diferentes.
Usaremos tanto la function declaration
función como el Constructor de función . Veremos cómo se comporta typeof
y instanceof
en esos dos escenarios diferentes.
Crear función utilizando la declaración de función:
function MyFunc(){ }
typeof Myfunc == ''function'' // true
MyFunc instanceof Function // false
La posible explicación para un resultado tan diferente es que, como hicimos una declaración de función, typeof
puede entender que es una función. typeof
que typeof
verifica si la expresión en la cual typeof es operativa, en nuestro caso MyFunc
implementó Call Method o no . Si implementa el método Call
, es una función. De lo contrario, no. Para aclaraciones, compruebe la especificación de ecmascript para typeof .
Crear una función utilizando el constructor de funciones:
var MyFunc2 = new Function(''a'',''b'',''return a+b'') // A function constructor is used
typeof MyFunc2 == ''function'' // true
MyFunc2 instanceof Function // true
Aquí, typeof
afirma que MyFunc2
es una función, así como también la instanceof
operador. Ya sabemos si typeof
verifica si MyFunc2
implementó el método Call
o no. Como MyFunc2
es una función e implementa el método call
, así es como typeof
sabe que es una función. Por otro lado, usamos el function constructor
para crear MyFunc2
, se convierte en una instancia del Function constructor
de Function constructor
Es por eso que instanceof
también se resuelve en true
.
¿Qué es más seguro de usar?
Como podemos ver en ambos casos, typeof
operator puede afirmar con éxito que estamos tratando con una función aquí, es más seguro que instanceof
. instanceof
fallará en caso de function declaration
de function declaration
porque function declarations
no son una instancia del Function constructor
de Function constructor
.
Mejores prácticas :
Como sugirió Gary Rafferty , la mejor manera debería ser usar tanto typeof como instanceof juntos.
function isFunction(functionItem) {
return typeof(functionItem) == ''function'' || functionItem instanceof Function;
}
isFunction(MyFunc) // invoke it by passing our test function as parameter
Actuación
typeof
es más rápido que instanceof
en situaciones donde ambos son aplicables.
Dependiendo de su motor, la diferencia de rendimiento a favor de typeof
podría ser de alrededor del 20% . ( Su kilometraje puede variar )
Aquí hay una prueba de referencia para 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
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"