¿Qué es un tipo? En pocas palabras, un tipo consiste en asignar un determinado significado a una secuencia binaria en la memoria. Por ejemplo, la secuencia binaria 0100 0000 0111 0000 0001 0101 0100 1011 1100 0110 1010 0111 1110 1111 1001 1110 es 4643234631018606494 si se ve como un tipo entero sin signo de 64 bits 54 reglas para la representación binaria de números de coma flotante (ver Apéndice 1) doble. precision El tipo de punto flotante es 257.331.
La mayoría de los lenguajes informáticos utilizan variables para almacenar y representar datos. Algunos lenguajes especifican un tipo de variable. Este tipo no se puede cambiar durante todo el programa (ya sea en tiempo de compilación o de ejecución). Por el contrario, las variables en JavaScript y algunos otros lenguajes pueden almacenar cualquier tipo y utilizan variables sin tipo. La existencia del tipo de variable no tiene nada que ver con la sintaxis. Por ejemplo, C# también proporciona variables de tipo var. Sin embargo, la siguiente declaración provocará un error en C#.
var a = 1;
a="cadena";
La razón es que la palabra clave var de C# solo omite la declaración del tipo de variable e infiere automáticamente el tipo de variable en función de la expresión de inicialización, por lo que la variable var de C# todavía tiene un tipo. En JavaScript, puedes asignar cualquier valor a una variable específica en cualquier momento, por lo que las variables de JavaScript no tienen tipo.
Según el método de diseño del sistema de tipos de lenguaje informático, se puede dividir en dos tipos: tipo fuerte y tipo débil. La diferencia entre los dos radica en si la conversión implícita entre diferentes tipos puede ser transparente para el usuario durante el cálculo. Desde la perspectiva del usuario, si un lenguaje puede convertir implícitamente todos sus tipos, cuando sus variables, expresiones, etc. estén involucradas en operaciones, incluso si el tipo es incorrecto, aún pueden obtener el tipo correcto mediante la conversión implícita. , es como si todos los tipos pudieran realizar todas las operaciones, por lo que dicho lenguaje se denomina débilmente tipado. Por el contrario, es posible que no haya necesariamente conversiones implícitas entre tipos en un lenguaje fuertemente tipado (por ejemplo, C++ es un lenguaje fuertemente tipado, pero double e int se pueden convertir entre sí en C++, pero se requiere una conversión entre double y any). tipo de puntero)
Los tipos pueden ayudar a los programadores a escribir programas correctos y actúan como restricciones en el proceso real de escritura de programas. La regla general es que cuanto más fuerte es la restricción, menos propensa a errores, pero más problemático es escribir el programa. Los lenguajes fuertemente tipados con variables que tienen tipos tienen las restricciones más fuertes, y el representante típico es C++. Los lenguajes débilmente tipados que tienen variables sin tipo tienen las restricciones más débiles, siendo JavaScript el representante típico. En JavaScript, debido a que las restricciones son relativamente débiles, es probable que ocurra este error:
var a =200;
varb="1";
var c = a + b;
Se podría esperar que c sea 201, pero en realidad es "2001", un error que nunca ocurre en lenguajes fuertemente tipados. Sin embargo, precisamente porque JavaScript no tiene estas restricciones, puede concatenar fácilmente tipos numéricos y de cadena. Por lo tanto, las limitaciones y la flexibilidad son siempre un conjunto de características que los diseñadores de lenguajes deben equilibrar.
Un tipo es una restricción que funciona mediante verificación de tipos. En diferentes idiomas, la verificación de tipos funciona en diferentes etapas, que se pueden dividir en verificación en tiempo de compilación y verificación en tiempo de ejecución. Para lenguajes interpretados como JavaScript, existen etapas similares al proceso de compilación, es decir, análisis léxico y análisis de sintaxis. Si la verificación de tipos de los lenguajes interpretados se completa durante el análisis de sintaxis o la etapa anterior, también se puede considerar. similar a la verificación en tiempo de compilación. Entonces, una afirmación más razonable es la verificación de tipos estáticos y la verificación de tipos dinámicos.
Curiosamente, aunque muchos lenguajes verifican los tipos en tiempo de compilación, su información de tipo aún se puede obtener en tiempo de ejecución. Por ejemplo, C # usa metadatos para guardar información de tipo durante el tiempo de ejecución, y los usuarios pueden obtener y usar información de tipo.
JavaScript prioriza la flexibilidad en todos los aspectos de su diseño, por lo que utiliza la verificación de tipos dinámica y no verifica los tipos activamente excepto cuando realiza muy pocas operaciones específicas. Puede obtener la información de tipo de cualquier variable o expresión en tiempo de ejecución y verificar su corrección a través de la lógica del programa.
Hay 9 tipos especificados en el estándar JavaScript: No definido Nulo Número de cadena booleana Finalización de lista de referencia de objeto
Entre ellos, los tres tipos de finalización de la lista de referencia solo se utilizan durante el tiempo de ejecución del análisis del lenguaje y no se puede acceder a ellos directamente desde el programa. No se presentarán aquí. A continuación podemos conocer estos seis tipos:
El tipo indefinido tiene solo un valor, indefinido, que es el valor cuando a la variable no se le asigna un valor. En JS, el objeto global tiene una propiedad indefinida que representa indefinido. De hecho, indefinido no es una palabra clave en JavaScript. asigne un valor a la propiedad global indefinida para cambiar su valor.
El tipo Null también tiene un solo valor, null, pero JavaScript le proporciona una palabra clave null para representar este valor único. La semántica del tipo Null es "una referencia de objeto vacía".
Booleano tiene dos valores: verdadero y falso
La interpretación formal del tipo String es una secuencia de tipos enteros sin signo de 16 bits, que en realidad se utiliza para representar información de texto codificada en UTF-16.
El número de JavaScript tiene un total de 18437736874454810627 (es decir, 264-253 +3) valores. El número de JavaScript se almacena en tipo de punto flotante de doble precisión, excepto que 9007199254740990 representa NaN, que cumple con IEEE 754 (consulte el Apéndice 1) y ocupa 64 bits y 8 bytes.
El tipo más complejo en JavaScript es Objeto, que es una colección desordenada de una serie de propiedades. La Función es un Objeto que implementa la propiedad privada [[llamada]]. El host de JavaScript también puede proporcionar algunos objetos especiales.
Hablé antes sobre los tipos especificados en el estándar JS. Sin embargo, un problema que no se puede ignorar es que el estándar JS está escrito para implementadores de JS, por ejemplo. Debido a que JS realiza operaciones, los tipos que no son de objeto se convertirán automáticamente en los objetos correspondientes, por lo que "str".length en realidad es equivalente a (new String("str")).length, se considera desde esta perspectiva. No es mala idea que ambos sean del mismo tipo. Usamos algunas características del lenguaje en JS para realizar la discriminación de tipos en tiempo de ejecución, pero los resultados de estos métodos son diferentes. Debe decidir cuál es mejor o peor.
Typeof es un operador en lenguaje JS. Desde su punto de vista literal, obviamente se usa para obtener el tipo. Según el estándar JavaScript, typeof obtiene la representación de cadena del nombre del tipo de variable. bool, número, indefinido, objeto, función y el estándar JavaScript permite a sus implementadores personalizar el tipo de valor de algunos objetos.
Existe una lista de descripciones en el estándar JS:
Tipo | Resultado |
Indefinido | "indefinido" |
Nulo | "objeto" |
Booleano | "booleano" |
Número | "número" |
Cadena | "cadena" |
Objeto (nativo y no implementa [[call]]) | "objeto" |
Objeto (nativo e implementa [[llamada]]) | "función" |
Objeto (anfitrión) | Dependiente de la implementación |
El siguiente ejemplo proviene de Rimifon de 51js, que muestra la situación en la que el resultado de typeof en IE produce "fecha" y "desconocido":
var xml=document.createElement("xml");
var rs=xml.recordset;
rs.Fields.Append("fecha", 7, 1);
rs.Fields.Append("bin", 205, 1);
rs.Open();
rs.AddNew();
rs.Fields.Item("fecha").Valor = 0;
rs.Fields.Item("bin").Valor = 21704;
rs.Actualizar();
var fecha = rs.Fields.Item("fecha").Valor;
var bin = rs.Fields.Item("bin").Valor;
rs.Cerrar();
alerta(fecha);
alerta(contenedor);
alert([tipo de fecha, tipo de contenedor]);
intentar{alert(date.getDate())}catch(err){alert(err.message)}
En realidad, hay muchas críticas sobre este método de juicio que se acerca más a la semántica de "tipo". Una de ellas es que no puede distinguir diferentes objetos entre la Nueva Cadena ("abc") y el nuevo Número (123) porque En. En la programación JS, a menudo se usa una gran cantidad de objetos diversos, y typeof solo puede dar un resultado vago de "objeto" para todos los objetos, lo que reduce en gran medida su practicidad.
El significado de instancia de se traduce al chino como "es una instancia de ...". Literalmente entendido, es un término basado en programación orientada a objetos basada en clases, y JS en realidad no proporciona soporte para la programación basada en clases. nivel de idioma. Aunque el estándar JavaScript no menciona una palabra, de hecho, el diseño de algunos objetos integrados y la configuración del operador sugieren una forma "oficial" de implementar clases, es decir, a partir del uso de funciones como clases, cuando actúa el nuevo operador. en la función, el atributo prototipo de la función se establece en el prototipo del objeto recién construido y la función misma se utiliza como constructor.
Por tanto, los objetos construidos a partir de la nueva operación de la misma función se consideran instancias de una clase. Lo que estos objetos tienen en común es: 1. Tienen el mismo prototipo y 2. Son procesados por el mismo constructor. Y instancia de es un operador que comprueba "si una instancia pertenece a una clase" junto con esta forma de implementar una clase. También se puede adivinar que es muy difícil verificar si un objeto ha sido procesado por un constructor, pero es mucho más fácil verificar cuál es su prototipo. Por lo tanto, la implementación de instancia de se entiende desde la perspectiva del prototipo, que es. verifique que el atributo [ [prototipo]] sea consistente con el prototipo de una función específica. Tenga en cuenta que [[prototipo]] aquí es una propiedad privada, a la que se puede acceder usando __proto__ en SpiderMonkey (que es el motor JS de Firefox).
El prototipo solo es significativo para el tipo de objeto descrito por el estándar, por lo que instancia de obtendrá falso para todos los objetos que no sean de objeto, e instancia de solo puede determinar si pertenece a un determinado tipo, pero no puede obtener el tipo. instancia de también es obvia. Puede distinguirse de un objeto construido a partir de una "clase" definida.
De hecho, se puede engañar a instancia de. Aunque el atributo privado [[prototipo]] del objeto que utiliza no se puede cambiar, el prototipo de la función es un atributo público. El siguiente código muestra cómo engañar a instancia de.
función ClaseA(){};
función ClaseB(){};
var o = new ClassA();//Construir un objeto de clase A
ClassB.prototype = ClassA.prototype; //Reemplazar ClassB.prototype;
alerta (o instancia de Clase B) // verdadero engaño exitoso - -!
Object.prototype.toString es originalmente difícil de llamar. Todas las clases integradas de JavaScript cubren el método toString. Para objetos construidos por clases no integradas, Object.prototype.toString solo puede obtener el [objeto] sin sentido. resultado. Por tanto, desde hace bastante tiempo no se ha descubierto el efecto mágico de esta función.
En el estándar, la descripción de Object.prototype.toString tiene solo 3 oraciones.
1. Obtenga el atributo [[clase]] de este objeto
2. Calcule una cadena concatenando las tres cadenas "[objeto", resultado(1) y "]"
3. Devuelve el resultado (2).
Obviamente, Object.prototype.toString en realidad solo obtiene el atributo [[class]] del objeto, pero no sé si es intencional. Se utilizarán todos los objetos de funciones integradas de JS String Number Array RegExp... cuando use new para construir objetos, establezca el atributo [[class]] para que el atributo [[class]] pueda usarse como una buena base para juzgar el tipo.
Debido a que Object.prototype.toString toma la propiedad de este objeto, puede especificar este objeto y luego obtener el tipo usando Object.prototype.toString.call u Object.prototype.toString.apply.
Aunque Object.prototype.toString es inteligente, no puede obtener el tipo de objeto construido por la función personalizada, porque la función personalizada no establece [[clase]] y no se puede acceder a esta propiedad privada en el programa. La mayor ventaja de Object.prototype.toString es que puede hacer que 1 y el nuevo Número (1) sean el mismo tipo de objeto. La mayoría de las veces, los dos se usan de la misma manera.
Sin embargo, vale la pena señalar que cuando el nuevo booleano (falso) participa en operaciones bool, el resultado es exactamente opuesto a falso. Si los dos se consideran del mismo tipo en este momento, fácilmente provocará errores difíciles de corregir. controlar.
Para comparar los tres tipos de métodos de juicio anteriores, hice una tabla para que todos puedan tener una comparación general de varios métodos. Para facilitar la comparación, he unificado los resultados obtenidos mediante varios métodos de juicio:
objeto | tipo de | instancia de | Objeto.prototipo.toString | estándar |
"abecedario" | Cadena | —— | Cadena | Cadena |
nueva cadena ("abc") | Objeto | Cadena | Cadena | Objeto |
función hola(){} | Función | Función | Función | Objeto |
123 | Número | —— | Número | Número |
nuevoNúmero(123) | Objeto | Número | Número | Objeto |
nueva matriz (1,2,3) | Objeto | Formación | Formación | Objeto |
nuevoMiTipo() | Objeto | Mi tipo | Objeto | Objeto |
nulo | Objeto | —— | Objeto | Nulo |
indefinido | Indefinido | —— | Objeto | Indefinido |
De hecho, es difícil decir cuál de los métodos anteriores es más razonable. Incluso las disposiciones del estándar solo reflejan el mecanismo de ejecución de JS en lugar de las mejores prácticas de uso. Mi opinión personal es restar importancia al concepto de "tipo" y centrarse más en las limitaciones de "cómo quiero usar este objeto". El uso de typeof estanceof para verificar puede lograr el mismo efecto que un lenguaje fuertemente tipado cuando sea necesario.
bit de signo: utilizado para representar signos positivos y negativos
exponente: usado para representar números de potencia
mantisa (mantisa): utilizada para indicar precisión