Qu'est-ce qu'un type ? En termes simples, un type consiste à attribuer une certaine signification à une séquence binaire en mémoire. Par exemple, la séquence binaire 0100 0000 0111 0000 0001 0101 0100 1011 1100 0110 1010 0111 1110 1111 1001 1110 est 4643234631018606494 si elle est considérée comme un type entier non signé de 64 bits. 54 règles de représentation binaire des nombres à virgule flottante (voir Annexe 1) double précision Le type à virgule flottante est 257.331.
La plupart des langages informatiques utilisent des variables pour stocker et représenter les données. Certains langages spécifient un type pour les variables. Ce type ne peut pas être modifié tout au long du programme (que ce soit au moment de la compilation ou de l'exécution). En revanche, les variables en JavaScript et dans certains autres langages peuvent stocker n'importe quel type et utilisent des variables non typées. Le fait que le type de variable existe n'a rien à voir avec la syntaxe. Par exemple, C# fournit également des variables de type var. Cependant, l'instruction suivante provoquera une erreur en C# :
var a = 1 ;
a="chaîne";
La raison en est que le mot-clé var de C# omet uniquement la déclaration du type de variable et déduit automatiquement le type de variable en fonction de l'expression d'initialisation, de sorte que la variable var de C# a toujours un type. En JavaScript, vous pouvez attribuer n'importe quelle valeur à une variable spécifique à tout moment, de sorte que les variables JavaScript ne sont pas typées.
Selon la méthode de conception du système de type langage informatique, il peut être divisé en deux types : le type fort et le type faible. La différence entre les deux réside dans la question de savoir si la conversion implicite entre différents types peut être transparente pour l'utilisateur lors du calcul. Du point de vue de l'utilisateur, si un langage peut convertir implicitement tous ses types, alors lorsque ses variables, expressions, etc. sont impliquées dans des opérations, même si le type est incorrect, ils peuvent toujours obtenir le type correct grâce à une conversion implicite pour l'utilisateur. , c'est comme si tous les types pouvaient effectuer toutes les opérations, c'est pourquoi un tel langage est appelé faiblement typé. En revanche, il n'y a pas nécessairement de conversions implicites entre les types dans un langage fortement typé (par exemple, C++ est un langage fortement typé, mais double et int peuvent être convertis l'un en l'autre en C++, mais un transtypage est requis entre double et any. type de pointeur).
Les types peuvent aider les programmeurs à écrire des programmes corrects et ils agissent comme des contraintes dans le processus réel d'écriture de programmes. La règle générale est que plus la contrainte est forte, moins elle est sujette aux erreurs, mais plus il est difficile d'écrire le programme. Les langages fortement typés avec des variables qui ont des types ont les contraintes les plus fortes, et le représentant typique est le C++. Les langages faiblement typés qui ont des variables non typées ont les contraintes les plus faibles, JavaScript étant le représentant typique. En JavaScript, les contraintes étant relativement faibles, cette erreur est susceptible de se produire :
var a = 200 ;
varb="1";
var c= une + b;
Vous pourriez vous attendre à ce que c soit 201, mais en fait il s'agit de "2001", une erreur qui ne se produit jamais dans les langages fortement typés. Cependant, précisément parce que JavaScript n'a pas ces contraintes, il peut facilement concaténer des types numériques et des types de chaînes. Par conséquent, les contraintes et la flexibilité constituent toujours un ensemble de fonctionnalités qui doivent être équilibrées pour les concepteurs de langages.
Un type est une contrainte qui fonctionne grâce à la vérification de type. Dans différents langages, la vérification de type fonctionne à différentes étapes, qui peuvent être divisées en vérification au moment de la compilation et en vérification au moment de l'exécution. Pour les langages interprétés comme JavaScript, il existe des étapes similaires au processus de compilation, à savoir l'analyse lexicale et l'analyse syntaxique. Si la vérification du type des langages interprétés est effectuée lors de l'analyse syntaxique ou de l'étape précédente, elle peut également être envisagée. similaire à la vérification au moment de la compilation. Une déclaration plus raisonnable est donc la vérification de type statique et la vérification de type dynamique.
Fait intéressant, bien que de nombreux langages vérifient les types au moment de la compilation, leurs informations de type peuvent toujours être obtenues au moment de l'exécution. Par exemple, C# utilise des métadonnées pour enregistrer les informations de type pendant l'exécution, les utilisateurs peuvent obtenir et utiliser les types via la réflexion.
JavaScript donne la priorité à la flexibilité dans tous les aspects de sa conception. Il utilise donc une vérification de type dynamique et ne vérifie pas activement les types, sauf lors de l'exécution de très peu d'opérations spécifiques. Vous pouvez obtenir les informations de type de n'importe quelle variable ou expression au moment de l'exécution et vérifier son exactitude via la logique du programme.
Il existe 9 types spécifiés dans la norme JavaScript : Non défini Null Booléen Chaîne Numéro Objet Référence Liste Achèvement
Parmi eux, les trois types de complétion de liste de référence ne sont utilisés que lors de l'exécution de l'analyse du langage et ne sont pas directement accessibles depuis le programme. Ils ne seront pas présentés ici. Ci-dessous, nous pouvons en apprendre davantage sur ces six types :
Le type Undéfini n'a qu'une seule valeur, undéfini, qui est la valeur lorsque aucune valeur n'est attribuée à la variable. Dans JS, l'objet global a une propriété undéfinie qui représente undéfini. En fait, undéfini n'est pas un mot-clé en JavaScript. attribuez une valeur à la propriété globale non définie pour modifier sa valeur.
Le type Null n'a également qu'une seule valeur, null, mais JavaScript lui fournit un mot-clé null pour représenter cette valeur unique. La sémantique du type Null est « une référence d'objet vide ».
Boolean a deux valeurs : vrai et faux
L'interprétation formelle du type String est une séquence de types entiers non signés de 16 bits, qui est en fait utilisée pour représenter des informations textuelles codées en UTF-16.
Le nombre JavaScript a un total de 18437736874454810627 (soit 264-253 +3) valeurs. Le numéro de JavaScript est stocké en type à virgule flottante double précision, sauf que 9007199254740990 représente NaN, qui est conforme à la norme IEEE 754 (voir Annexe 1) et occupe 64 bits et 8 octets.
Le type le plus complexe en JavaScript est Object, qui est une collection non ordonnée d'une série de propriétés. Function est un objet qui implémente la propriété privée [[call]].
J'ai déjà parlé des types spécifiés dans la norme JS. Cependant, un problème qui ne peut être ignoré est que la norme JS est écrite pour les implémenteurs JS, par exemple. , parce que JS est Lors de l'exécution de l'opération, les types non-Object seront automatiquement convertis en objets correspondants, donc "str".length est en fait équivalent à (new String("str")).length De ce point de vue, il est considéré. Ce n'est pas une mauvaise idée que les deux soient du même type. Nous utilisons certaines fonctionnalités du langage JS pour effectuer une discrimination des types d'exécution, mais les résultats de ces méthodes sont différents. Vous devez décider laquelle est la meilleure ou la pire.
Typeof est un opérateur en langage JS. De son point de vue littéral, il est évidemment utilisé pour obtenir le type. Selon le standard JavaScript, typeof obtient la représentation sous forme de chaîne du nom du type de variable. bool, number, undefined, object, function et le standard JavaScript permet à ses implémenteurs de personnaliser le type de valeur de certains objets.
Il existe une telle liste de descriptions dans la norme JS :
Taper | Résultat |
Indéfini | "indéfini" |
Nul | "objet" |
Booléen | "booléen" |
Nombre | "nombre" |
Chaîne | "chaîne" |
Objet (natif et n'implémente pas [[call]]) | "objet" |
Objet (natif et implémente [[call]]) | "fonction" |
Objet (hôte) | Dépend de la mise en œuvre |
L'exemple suivant provient de Rimifon de 51js, qui montre la situation où le résultat de typeof dans IE produit "date" et "inconnu" :
var xml=document.createElement("xml");
var rs=xml.recordset;
rs.Fields.Append("date", 7, 1);
rs.Fields.Append("bin", 205, 1);
rs.Open();
rs.AddNew();
rs.Fields.Item("date").Value = 0;
rs.Fields.Item("bin").Value = 21704;
rs.Update();
var date = rs.Fields.Item("date").Value;
var bin = rs.Fields.Item("bin").Value;
rs.Close();
alerte (date);
alerte (bac);
alert([type de date, type de bac]);
essayez{alert(date.getDate())}catch(err){alert(err.message)}
Il existe en fait de nombreuses critiques à propos de cette méthode de jugement qui est la plus proche de la sémantique du « type ». L'une d'elles est qu'elle ne peut pas distinguer différents objets New String (« abc ») et le nouveau Number (123) ne peut pas être distingué à l'aide de typeof. En programmation JS, un grand nombre d'objets divers sont souvent utilisés, et typeof ne peut donner qu'un vague résultat « objet » pour tous les objets, ce qui réduit considérablement sa praticité.
La signification de instanceof est traduite en chinois par "est une instance de..." Littéralement compris, il s'agit d'un terme basé sur la programmation orientée objet basée sur les classes, et JS ne fournit pas réellement de support pour la programmation basée sur les classes. niveau de langue. Bien que le standard JavaScript ne mentionne pas un mot, en fait, la conception de certains objets intégrés et les paramètres de l'opérateur font tous allusion à une manière « officielle » d'implémenter les classes, c'est-à-dire d'utiliser des fonctions en tant que classes, lorsque le nouvel opérateur agit. sur la fonction, l'attribut prototype de la fonction est défini sur le prototype de l'objet nouvellement construit et la fonction elle-même est utilisée comme constructeur.
Par conséquent, les objets construits à partir de la nouvelle opération de la même fonction sont considérés comme des instances d'une classe. Ce que ces objets ont en commun est : 1. Ils ont le même prototype et 2. Ils sont traités par le même constructeur. Et instanceof est un opérateur qui vérifie "si une instance appartient à une classe" en conjonction avec cette façon d'implémenter une classe. Vous pouvez également deviner qu'il est très difficile de vérifier si un objet a été traité par un constructeur, mais il est beaucoup plus facile de vérifier quel est son prototype. Par conséquent, l'implémentation d'instanceof est comprise du point de vue du prototype, qui consiste à. vérifiez que l'attribut [ [prototype]] est cohérent avec le prototype d'une fonction spécifique. Notez que [[prototype]] ici est une propriété privée, accessible en utilisant __proto__ dans SpiderMonkey (qui est le moteur JS de Firefox).
Le prototype n'a de sens que pour le type d'objet décrit par la norme, donc instanceof obtiendra faux pour tous les objets non-objet, et instanceof ne peut déterminer que s'il appartient à un certain type, mais ne peut pas obtenir le type. Cependant, l'avantage de. instanceof est également évident. Il peut se distinguer. Un objet construit à partir d'une "classe" définie.
En fait, instanceof peut être trompé. Bien que l'attribut privé [[prototype]] de l'objet qu'il utilise ne puisse pas être modifié, le prototype de la fonction est un attribut public. Le code suivant montre comment tromper instanceof.
fonction ClasseA(){};
fonction ClasseB(){};
var o = new ClassA();//Construire un objet de classe A
ClassB.prototype = ClassA.prototype; //Remplacer ClassB.prototype
alert(o instanceof ClassB)//véritable tromperie réussie - - !
Object.prototype.toString est à l'origine difficile à appeler.Toutes les classes intégrées JavaScript couvrent la méthode toString Pour les objets construits par des classes non intégrées, Object.prototype.toString ne peut obtenir que le [object Object ] ce genre de sens. résultat. Par conséquent, depuis longtemps, l’effet magique de cette fonction n’a pas été découvert.
Dans la norme, la description de Object.prototype.toString ne comporte que 3 phrases
1. Obtenez l'attribut [[class]] de cet objet
2. Calculez une chaîne en concaténant les trois chaînes "[object", result(1) et "]"
3. Renvoyez le résultat (2).
De toute évidence, Object.prototype.toString obtient simplement l'attribut [[class]] de l'objet, mais je ne sais pas si c'est intentionnel. Tous les objets de fonction intégrés à JS String Number Array RegExp... seront tous utilisés. lors de l'utilisation de new pour construire des objets, définissez l'attribut [[class]] afin que l'attribut [[class]] puisse être utilisé comme une bonne base pour juger du type.
Étant donné que Object.prototype.toString prend la propriété de cet objet, vous pouvez spécifier cet objet, puis obtenir le type à l'aide de Object.prototype.toString.call ou Object.prototype.toString.apply.
Bien que Object.prototype.toString soit intelligent, il ne peut pas obtenir le type d'objet construit par la fonction personnalisée, car la fonction personnalisée ne définit pas [[class]] et cette propriété privée n'est pas accessible dans le programme. Le plus grand avantage de Object.prototype.toString est qu'il peut faire en sorte que 1 et new Number(1) soient le même type d'objet. La plupart du temps, les deux sont utilisés de la même manière.
Cependant, il convient de noter que lorsque new Boolean(false) participe à des opérations booléennes, le résultat est exactement le contraire de false. Si les deux sont considérés comme du même type à ce moment-là, cela entraînera facilement des erreurs difficiles à générer. vérifier.
Afin de comparer les trois types de méthodes de jugement ci-dessus, j'ai réalisé un tableau afin que chacun puisse avoir une comparaison globale de plusieurs méthodes. Afin de faciliter la comparaison, j'ai unifié les résultats obtenus par plusieurs méthodes de jugement :
objet | type de | instance de | Objet.prototype.toString | standard |
"abc" | Chaîne | —— | Chaîne | Chaîne |
nouvelle chaîne ("abc") | Objet | Chaîne | Chaîne | Objet |
fonction bonjour(){} | Fonction | Fonction | Fonction | Objet |
123 | Nombre | —— | Nombre | Nombre |
nouveauNuméro(123) | Objet | Nombre | Nombre | Objet |
nouveau tableau (1,2,3) | Objet | Tableau | Tableau | Objet |
nouveauMonType() | Objet | MonType | Objet | Objet |
nul | Objet | —— | Objet | Nul |
indéfini | Indéfini | —— | Objet | Indéfini |
En fait, il est difficile de dire laquelle des méthodes ci-dessus est la plus raisonnable. Même les dispositions de la norme ne reflètent que le mécanisme d'exécution de JS plutôt que les meilleures pratiques d'utilisation. Mon opinion personnelle est de minimiser le concept de "type" et de me concentrer davantage sur les contraintes de "comment puis-je utiliser cet objet". L'utilisation de typeof et instanceof pour vérifier peut obtenir le même effet qu'un langage fortement typé si nécessaire.
bit de signe : utilisé pour représenter les signes positifs et négatifs
exposant : utilisé pour représenter les nombres de puissance
mantisse (mantisse) : utilisée pour indiquer la précision