web-dev-qa-db-fra.com

Le JavaScript est-il interprété par la conception?

Je suis prudent de poser cette question, car elle peut sembler trop fastidieuse. Je viens d'ouvrir JavaScript: le guide définitif, et il indique la première page du chapitre 1

"JavaScript est un langage de programmation interprété de haut niveau, dynamique et non typé"

Dois-je donc considérer que la partie interprétée est une exigence dans la spécification du langage, ou est-il trompeur de dire que le langage est un langage de programmation interprété en respectant la différence entre un langage et ses nombreuses implémentations?

Il n'y a apparemment pas de compilateurs statiques pour JavaScript - https://stackoverflow.com/questions/1118138/is-there-a-native-machine-code-compiler-for-javascript alors peut-être que c'est juste un reflet de cela.

75
Matt Esch

Dois-je donc considérer que la partie interprétée est une exigence dans la spécification du langage, ou est-il trompeur de dire que le langage est un langage de programmation interprété en respectant la différence entre un langage et ses nombreuses implémentations?

Les geeks du langage EcmaScript utilisent souvent le terme "interprète ES" pour faire référence à une implémentation d'EcmaScript, mais le spec n'utilise pas ce terme. Le aperçu de la langue décrit en particulier la langue en termes agnostiques:

ECMAScript est basé sur des objets: le langage de base et les fonctionnalités Host sont fournis par des objets, et un programme ECMAScript est un cluster d'objets communicants.

EcmaScript suppose donc un "environnement hôte" qui est défini comme un fournisseur de définitions d'objets, y compris toutes celles qui autorisent les E/S ou tout autre lien vers le monde extérieur, mais ne nécessite pas d'interprète.

La sémantique des instructions et des expressions dans le langage est définie en termes de spécification d'achèvement qui sont trivialement implémentées dans un interpréteur, mais la spécification ne l'exige pas.

8.9 Le type de spécification d'achèvement

Le type Achèvement est utilisé pour expliquer le comportement des instructions (break, continue, return et throw) qui effectuent des transferts de contrôle non locaux. Les valeurs du type Completion sont des triplets de la forme ( type, value, target), où type est l'un de normal , pause , continuer , retourner , ou lancer , value est n'importe quelle valeur de langage ECMAScript ou vide , et target est n'importe quel identifiant ECMAScript ou vide .

Le terme "achèvement brutal" fait référence à tout achèvement avec un type autre que normal .

Les transferts de contrôle non locaux peuvent être convertis en tableaux d'instructions avec des sauts permettant une compilation native ou en octets.

"Moteur EcmaScript" pourrait être une meilleure façon d'exprimer la même idée.


Il n'y a apparemment pas de compilateurs statiques pour JavaScript

Ce n'est pas vrai. "L'interpréteur" V8 compile en code natif en interne, Rhino compile éventuellement en Java bytecode en interne, et divers interprètes Mozilla ({Trace, Spider, Jager} Monkey) utilisent un compilateur JIT).

V8 :

V8 augmente les performances en compilant JavaScript en code machine natif avant de l'exécuter, par rapport à l'exécution de bytecode ou à son interprétation.

Rhino :

public final void setOptimizationLevel(int optimizationLevel)

Définissez le niveau d'optimisation actuel. Le niveau d'optimisation devrait être un entier compris entre -1 et 9. Toute valeur négative sera interprétée comme -1, et toute valeur supérieure à 9 sera interprétée comme 9. Un niveau d'optimisation de -1 indique que le mode d'interprétation sera toujours utilisé. Les niveaux 0 à 9 indiquent que des fichiers de classe peuvent être générés. Des niveaux d'optimisation plus élevés compromettent les performances de compilation pour les performances d'exécution. Le niveau d'optimisation ne peut pas être supérieur à -1 si le package d'optimisation n'existe pas au moment de l'exécution.

TraceMonkey :

TraceMonkey ajoute une compilation de code natif au moteur JavaScript® de Mozilla (connu sous le nom de "SpiderMonkey"). Il est basé sur une technique développée à l'UC Irvine appelée "arbres de trace", et s'appuyant sur du code et des idées partagées avec le projet Tamarin Tracing. Le résultat net est une augmentation de vitesse massive à la fois dans le navigateur chrome et le contenu de la page Web.

51
Mike Samuel

Le JavaScript V8 VM utilisé dans Chrome n'inclut pas d'interprète. Au lieu de cela, il se compose de deux compilateurs et compile le code à la volée. L'un des compilateurs s'exécute rapidement mais génère du code inefficace, l'autre est un compilateur d'optimisation.

Je peux comprendre pourquoi certaines personnes considéreraient cette "tricherie", puisque V8 prend le code source en entrée à chaque exécution du code et que l'utilisateur doit avoir installé V8. Mais considérons un compilateur qui émet un exécutable qui comprend un interpréteur complet et un bytecode. Vous auriez alors un programme autonome. Ce ne serait tout simplement pas très efficace.

21
Jørgen Fogh

L'émergence de compilateurs JIT pour les langages de script a brouillé la frontière entre la compilation et l'interprétation au point que la question ne signifie pas grand-chose. S'agit-il uniquement d'interprétation lorsque le moteur lit une ligne de code et l'exécute immédiatement? (Les scripts shell sont toujours généralement implémentés de cette façon.) S'agit-il d'une interprétation lorsque le moteur prend le fichier entier, le compile immédiatement en un code d'octet, puis interprète le code d'octet? (Le moteur Mozilla de la première étape fonctionne de cette façon, tout comme CPython.) S'agit-il d'une interprétation lorsque le moteur analyse une fonction à la fois et la compile JIT en code natif? Qu'en est-il des moteurs qui compilent le fichier entier en code octet, puis JIT une fonction à la fois selon les besoins? (La plupart des moteurs de script fonctionnent de cette façon de nos jours, et le principal Java VM fonctionne également de cette façon, sauf que la compilation en code octet se produit à l'avance).)

Il existe de nombreuses nuances entre la compilation et l'interprétation.

Je pense que la définition la plus utile pour l'interprétation est "est alimenté le code source du programme au moment de l'exécution, sans étape distincte d'avance". Selon cette définition, tous les moteurs JavaScript sont des interprètes. Mais ce n'est certainement pas la seule définition possible de l'interprétation.

Mais JavaScript est-il conçu pour l'interprétation? D'une certaine manière, oui: il a une fonction eval ainsi que le constructeur Function que vous pouvez donner au code du programme sous forme de chaîne qui sera exécutée. La possibilité de construire dynamiquement du code de programme au moment de l'exécution nécessite que le moteur soit capable d'interpréter le code source. Mais cela ne signifie pas que vous ne pouvez pas faire tout le reste à l'avance. Même dans un langage compilé comme C++ et C #, vous pouvez prendre le code source, le compiler en mémoire dans un nouveau code machine, puis l'exécuter. Il existe même des bibliothèques pour cela: LLVM + Clang en C++ et le projet Roslyn en C #.

De plus, le mécanisme de livraison pour JavaScript est le code source; il n'y a aucune forme de code d'octet reconnue. C # et Java ont leur code d'octet officiel, et tout le monde s'attend à ce que C++ soit fourni comme code machine. Mais ce n'est toujours pas un aspect inhérent si le langage, juste un scénario d'utilisation dominant. En fait, Le code ActionScript proche de JavaScript dans Flash est en fait fourni sous forme de code octet (le compilateur Flash précompile tous les scripts).

19
Sebastian Redl

Il n'y a pas de définition totalement convenue de "interprété" par rapport à "compilé". Dans la distinction classique, les langages compilés produisent un exécutable binaire autonome, tandis que les langages interprétés nécessitent un runtime déployé pour exécuter le code. Les machines virtuelles, le bytecode, etc. brouillent la distinction.

Mais voici une définition peut-être utile: Un langage interprété est un langage où le langage d'exécution standard est capable de prendre du texte de code source en entrée et de l'exécuter. Par cette définition, les scripts Perl, Python, Ruby, JavaScript et Shell et similaires sont interprétés (même s'ils utilisent des étapes intermédiaires comme le bytecode ou même le code natif). Java, C #, C etc. ne le sont pas. Et JavaScript est par définition interprété, même si la spécification n'utilise pas le mot exact.

4
JacquesB