O que é um tipo? Simplificando, um tipo atribui um certo significado a uma sequência binária na memória. Por exemplo, a sequência binária 0100 0000 0111 0000 0001 0101 0100 1011 1100 0110 1010 0111 1110 1111 1001 1110 é 4643234631018606494 se vista como um tipo inteiro sem sinal de 64 bits. 54 regras para representação binária de números de ponto flutuante (ver Apêndice 1) duplo precisão O tipo de ponto flutuante é 257.331.
A maioria das linguagens de computador usa variáveis para armazenar e representar dados. Algumas linguagens especificam um tipo para variáveis. Este tipo não pode ser alterado ao longo do programa (seja em tempo de compilação ou em tempo de execução). Por outro lado, variáveis em JavaScript e em algumas outras linguagens podem armazenar qualquer tipo e usam variáveis não digitadas. A existência do tipo de variável não tem nada a ver com a sintaxe. Por exemplo, C# também fornece variáveis do tipo var. No entanto, a instrução a seguir causará um erro em C#:
var a=1;
a="string";
O motivo é que a palavra-chave var do C# apenas omite a declaração do tipo de variável e infere automaticamente o tipo da variável com base na expressão de inicialização, portanto, a variável var do C# ainda tem um tipo. Em JavaScript, você pode atribuir qualquer valor a uma variável específica a qualquer momento, portanto, as variáveis JavaScript não são digitadas.
De acordo com o método de design do sistema de tipo de linguagem de computador, ele pode ser dividido em dois tipos: tipo forte e tipo fraco. A diferença entre os dois reside em saber se a conversão implícita entre diferentes tipos pode ser transparente para o usuário durante o cálculo. Do ponto de vista do usuário, se uma linguagem pode converter implicitamente todos os seus tipos, então quando suas variáveis, expressões, etc. estão envolvidas em operações, mesmo que o tipo esteja incorreto, eles ainda podem obter o tipo correto por meio da conversão implícita para o usuário. , é como se todos os tipos pudessem realizar todas as operações, então tal linguagem é chamada de tipagem fraca. Em contraste, pode não haver necessariamente conversões implícitas entre tipos em uma linguagem fortemente tipada (por exemplo, C++ é uma linguagem fortemente tipada, mas double e int podem ser convertidos entre si em C++, mas é necessária uma conversão entre double e qualquer tipo de ponteiro)
Os tipos podem ajudar os programadores a escrever programas corretos e atuam como restrições no processo real de escrita de programas. A regra geral é que quanto mais forte a restrição, menos propensa a erros ela será, mas mais problemático será escrever o programa. Linguagens fortemente tipadas com variáveis que possuem tipos têm as restrições mais fortes, e o representante típico é C++. Linguagens de tipagem fraca que possuem variáveis não tipadas têm as restrições mais fracas, sendo o JavaScript o representante típico. Em JavaScript, como as restrições são relativamente fracas, este erro pode ocorrer:
var a =200;
varb="1";
var c= a + b;
Você pode esperar que c seja 201, mas na verdade é "2001", um erro que nunca ocorre em linguagens fortemente tipadas. No entanto, precisamente porque o JavaScript não possui essas restrições, ele pode concatenar facilmente tipos numéricos e de string. Portanto, restrições e flexibilidade são sempre um conjunto de características que precisam ser equilibradas para designers de linguagens.
Um tipo é uma restrição que funciona por meio da verificação de tipo. Em diferentes linguagens, a verificação de tipo funciona em diferentes estágios, que podem ser divididos em verificação em tempo de compilação e verificação em tempo de execução. Para linguagens interpretadas como JavaScript, existem etapas semelhantes ao processo de compilação, nomeadamente análise lexical e análise sintática. Se a verificação de tipo das linguagens interpretadas for concluída durante a análise sintática ou na etapa anterior, ela também pode ser considerada. semelhante à verificação em tempo de compilação. Portanto, uma afirmação mais razoável é a verificação de tipo estático e a verificação de tipo dinâmico.
Curiosamente, embora muitas linguagens verifiquem os tipos em tempo de compilação, suas informações de tipo ainda podem ser obtidas em tempo de execução. Por exemplo, C# usa metadados para salvar informações de tipo.
O JavaScript prioriza a flexibilidade em todos os aspectos de seu design, por isso usa verificação dinâmica de tipos e não verifica ativamente os tipos, exceto quando executa poucas operações específicas. Você pode obter as informações de tipo de qualquer variável ou expressão em tempo de execução e verificar sua exatidão por meio da lógica do programa.
Existem 9 tipos especificados no padrão JavaScript: Indefinido Nulo Booleano String Número Objeto Conclusão da lista de referência
Entre eles, os três tipos de Conclusão da Lista de Referência são usados apenas durante o tempo de execução da análise de linguagem e não podem ser acessados diretamente do programa. Abaixo podemos aprender sobre esses seis tipos:
O tipo Indefinido possui apenas um valor, indefinido, que é o valor quando a variável não recebe um valor. Em JS, o objeto global possui uma propriedade indefinida que representa indefinido. atribua um valor à propriedade global indefinida para alterar seu valor.
O tipo Null também possui apenas um valor, null, mas o JavaScript fornece uma palavra-chave null para representar esse valor exclusivo. A semântica do tipo Null é "uma referência de objeto vazia".
Boolean tem dois valores: verdadeiro e falso
A interpretação formal do tipo String é uma sequência de tipos inteiros sem sinal de 16 bits, que na verdade é usada para representar informações de texto codificadas em UTF-16.
O número do JavaScript tem um total de 18437736874454810627 (ou seja, 264-253 +3) valores. O número do JavaScript é armazenado no tipo de ponto flutuante de precisão dupla, exceto que 9007199254740990 representa NaN, que está em conformidade com IEEE 754 (consulte o Apêndice 1) e ocupa 64 bits e 8 bytes.
O tipo mais complexo em JavaScript é Object, que é uma coleção não ordenada de uma série de propriedades. Function é um Object que implementa a propriedade privada [[call]].
Já falei sobre os tipos especificados no padrão JS. No entanto, uma questão que não pode ser ignorada é que o padrão JS é escrito para implementadores de JS, os tipos não precisam necessariamente ser definidos de acordo com o padrão. , porque JS é ao executar a operação, os tipos não-objeto serão automaticamente convertidos em objetos correspondentes, então "str".length é na verdade equivalente a (new String("str")).length. Não é uma má ideia que ambos sejam do mesmo tipo. Usamos alguns recursos de linguagem em JS para realizar a discriminação do tipo de tempo de execução, mas os resultados desses métodos são diferentes.
Typeof é um operador em linguagem JS, do ponto de vista literal, é obviamente usado para obter o tipo. De acordo com o padrão JavaScript, typeof obtém a representação de string do nome do tipo de variável. bool, número, indefinido, objeto, função e o padrão JavaScript permitem que seus implementadores personalizem o valor typeof de alguns objetos.
Existe uma lista de descrições no padrão JS:
Tipo | Resultado |
Indefinido | "indefinido" |
Nulo | "objeto" |
Booleano | "booleano" |
Número | "número" |
Corda | "corda" |
Objeto (nativo e não implementa [[call]]) | "objeto" |
Objeto (nativo e implementa [[call]]) | "função" |
Objeto (host) | Dependente da implementação |
O exemplo a seguir vem do Rimifon do 51js, que mostra a situação em que o resultado de typeof no IE produz “data” e “desconhecido”:
var xml=document.createElement("xml");
var rs=xml.recordset;
rs.Fields.Append("data", 7, 1);
rs.Fields.Append("bin", 205, 1);
rs.Open();
rs.AddNew();
rs.Fields.Item("data").Valor = 0;
rs.Fields.Item("bin").Valor = 21704;
rs.Atualização();
var data = rs.Fields.Item("data").Valor;
var bin = rs.Fields.Item("bin").Valor;
rs.Fechar();
alerta(data);
alerta(lixo);
alert([tipo de data, tipo de bin]);
tente{alert(date.getDate())}catch(err){alert(err.message)}
Na verdade, existem muitas críticas sobre este método de julgamento que está mais próximo da semântica de "tipo". Uma delas é que ele não pode distinguir objetos diferentes ("abc") e novo número (123) usando typeof. Programação JS, um grande número de vários objetos são frequentemente usados, e typeof só pode fornecer um "objeto" de resultado vago para todos os objetos, o que reduz bastante sua praticidade.
O significado de instanceof é traduzido para o chinês como "é uma instância de..." Literalmente entendido, é um termo baseado em programação orientada a objetos baseada em classes, e JS na verdade não fornece suporte para programação baseada em classes. nível de linguagem. Embora o padrão JavaScript não mencione uma palavra, na verdade, o design de alguns objetos integrados e configurações de operadores sugerem uma maneira "oficial" de implementar classes, ou seja, usando funções como classes, quando o novo operador atua na função, o atributo protótipo da função é definido como o protótipo do objeto recém-construído e a própria função é usada como construtor.
Portanto, objetos construídos a partir da nova operação da mesma função são considerados instâncias de uma classe. O que esses objetos têm em comum é: 1. Possuem o mesmo protótipo e 2. São processados pelo mesmo construtor. E instanceof é um operador que verifica "se uma instância pertence a uma classe" em conjunto com esta forma de implementar uma classe. Você também pode adivinhar que é muito difícil verificar se um objeto foi processado por um construtor, mas é muito mais fácil verificar qual é o seu protótipo. Portanto, a implementação de instanceof é entendida da perspectiva do protótipo, que é. verifique se o atributo [[prototype]] é consistente com o protótipo de uma função específica. Observe que [[prototype]] aqui é uma propriedade privada, que pode ser acessada usando __proto__ no SpiderMonkey (que é o mecanismo JS do Firefox).
O protótipo só é significativo para o tipo Object descrito pelo padrão, então instanceof será falso para todos os objetos que não sejam Object, e instanceof só pode determinar se pertence a um determinado tipo, mas não pode obter a vantagem de. instanceof também é óbvio. Ele pode se distinguir. Um objeto construído a partir de uma "classe" definida.
Na verdade, instanceof pode ser enganado. Embora o atributo privado [[prototype]] do objeto que ele usa não possa ser alterado, o protótipo da função é um atributo público.
função ClasseA(){};
função ClasseB(){};
var o = new ClassA(); //Constrói um objeto da classe A
ClassB.prototype = ClassA.prototype; //Substituir ClassB.prototype
alert(o instanceof ClassB) //true engano bem-sucedido - -!
Object.prototype.toString é originalmente difícil de chamar. Todas as classes internas do JavaScript cobrem o método toString. Para objetos construídos por classes não integradas, Object.prototype.toString só pode obter o [objeto Object] sem sentido. resultado. Portanto, há muito tempo o efeito mágico desta função não foi descoberto.
No padrão, a descrição de Object.prototype.toString tem apenas 3 frases
1. Obtenha o atributo [[class]] deste objeto
2. Calcule uma string concatenando as três strings "[objeto", resultado(1) e "]"
3. Retorne o resultado (2).
Obviamente, Object.prototype.toString na verdade apenas obtém o atributo [[class]] do objeto, mas não sei se é intencional. Todos os objetos de função integrados do JS String Number Array RegExp... serão todos usados. ao usar new para construir objetos. Defina o atributo [[class]] para que o atributo [[class]] possa ser usado como uma boa base para julgar o tipo.
Como Object.prototype.toString usa a propriedade deste objeto, você pode especificar esse objeto e obter o tipo usando Object.prototype.toString.call ou Object.prototype.toString.apply.
Embora Object.prototype.toString seja inteligente, ele não pode obter o tipo de objeto construído pela função customizada, porque a função customizada não define [[class]] e esta propriedade privada não pode ser acessada no programa. A maior vantagem de Object.prototype.toString é que ele pode tornar 1 e new Number(1) o mesmo tipo de objeto. Na maioria das vezes, os dois são usados da mesma maneira.
No entanto, é importante notar que quando new Boolean(false) participa de operações bool, o resultado é exatamente o oposto de false. Se os dois forem considerados do mesmo tipo neste momento, isso levará facilmente a erros difíceis de serem corrigidos. verificar.
Para comparar os três tipos de métodos de julgamento acima, fiz uma tabela para que todos possam ter uma comparação geral dos vários métodos. Para facilitar a comparação, unifiquei os resultados obtidos por diversos métodos de julgamento:
objeto | tipo de | instância de | Objeto.prototype.toString | padrão |
"abc" | Corda | —— | Corda | Corda |
nova String("abc") | Objeto | Corda | Corda | Objeto |
função olá(){} | Função | Função | Função | Objeto |
123 | Número | —— | Número | Número |
novoNúmero(123) | Objeto | Número | Número | Objeto |
nova matriz (1,2,3) | Objeto | Variedade | Variedade | Objeto |
novoMeuTipo() | Objeto | Meu tipo | Objeto | Objeto |
nulo | Objeto | —— | Objeto | Nulo |
indefinido | Indefinido | —— | Objeto | Indefinido |
Na verdade, é difícil dizer qual dos métodos acima é mais razoável. Mesmo as disposições do padrão refletem apenas o mecanismo de tempo de execução do JS, e não as melhores práticas de uso. Minha opinião pessoal é minimizar o conceito de "tipo" e focar mais nas restrições de "como desejo usar este objeto". Usar typeof e instanceof para verificar pode obter o mesmo efeito que uma linguagem fortemente tipada quando necessário.
bit de sinal: usado para representar sinais positivos e negativos
expoente: usado para representar números de potência
mantissa (mantissa): usado para indicar precisão