Section courante

A propos

Section administrative du site

Les premiers pas

Cette page présente certains concepts clefs de V8 et fournit un exemple «bonjour» pour vous aider à démarrer avec le code V8.

Examinons un exemple Bonjour, le monde prenant une instruction JavaScript comme paramètre de chaîne de caractères, l'exécute en tant que code JavaScript et affiche le résultat sur la sortie standard.

Tout d'abord, quelques concepts clefs :

Exécutez un exemple

Suivez les étapes ci-dessous pour exécuter l'exemple vous-même :

Si vous recherchez un exemple synchronisé avec la branche principale, consultez le fichier hello-world.cc. Il s'agit d'un exemple très simple et vous souhaiterez probablement faire plus que simplement exécuter des scripts sous forme de chaînes de caractères.

Plus d'exemples de code

Les exemples suivants sont fournis dans le cadre du téléchargement du code source :

Fichier Description
process.cc Cet exemple fournit le code nécessaire pour étendre une application hypothétique de traitement de requêtes HTTP (pouvant faire partie d'un serveur Web, par exemple) afin qu'elle soit scriptable. Il prend un script JavaScript comme paramètre, devant fournir une fonction appelée Process. La fonction Process de JavaScript peut être utilisée pour, par exemple, collecter des informations telles que le nombre de vues obtenus par chaque page servie par le serveur Web fictif.
shell.cc Cet exemple prend les noms de fichiers comme paramètres, puis lit et exécute leur contenu. Comprend une prompt de commande à laquelle vous pouvez saisir des extraits de code JavaScript étant ensuite exécutés. Dans cet exemple, des fonctions supplémentaires telles que print sont également ajoutées à JavaScript via l'utilisation de modèles d'objets et de fonctions.

Notion avancé

Maintenant que vous êtes familiarisé avec l'utilisation de V8 en tant que machine virtuelle autonome et avec certains concepts clefs de V8 tels que les descripteurs, les portées et les contextes, examinons ces concepts plus en détail et introduisons quelques autres concepts essentiels à l'intégration de V8 dans votre propre application C++.

L'API de V8 fournit des fonctions pour compiler et exécuter des scripts, accéder aux méthodes et structures de données C++, gérer les erreurs et activer les contrôles de sécurité. Votre application peut utiliser V8 comme n'importe quelle autre bibliothèque C++. Votre code C++ accède à V8 via l'API de V8 en incluant l'entête de fichier include/v8.h.

Descripteurs et ramasse-miette

Un descripteur fournit une référence à l'emplacement d'un objet JavaScript dans la mémoire de tas. Le ramasse-miettes de V8 récupère la mémoire utilisée par les objets n'étant plus accessibles. Pendant le processus de ramasse-miettes, le ramasse-miettes déplace souvent les objets vers différents emplacements dans la mémoire de tas. Lorsque le ramasse-miettes déplace un objet, il met également à jour tous les descripteurs faisant référence à l'objet avec le nouvel emplacement de l'objet.

Un objet est considéré comme miettes s'il est inaccessible depuis JavaScript et qu'aucun descripteur ne fait référence à lui. De temps en temps, le ramasse-miettes supprime tous les objets considérés comme des miettes. Le mécanisme de ramasse-miettes de V8 est essentiel aux performances de V8.

Il existe plusieurs types de descripteurs :

Bien sûr, la création d'un descripteur local à chaque fois que vous créez un objet peut entraîner de nombreux descripteurs ! C'est là que les portées de descripteurs sont très utiles. Vous pouvez considérer une portée de descripteur comme un conteneur contenant de nombreux descripteurs. Lorsque le destructeur de la portée de descripteur est appelé, tous les descripteurs créés dans cette portée sont supprimés de la pile. Comme vous vous en doutez, cela a pour résultat que les objets vers lesquels les descripteurs pointent sont éligibles à la suppression de la mémoire de tas par le ramasse-miettes.

Lorsque le destructeur HandleScope::~HandleScope est appelé, la portée du descripteur est supprimée. Les objets référencés par des descripteurs dans la portée du descripteur supprimé sont éligibles pour suppression dans le prochain ramasse-miettes s'il n'y a pas d'autres références à eux. Le ramasse-miettes peut également supprimer les objets source_obj et script_obj de la mémoire de tas car ils ne sont plus référencés par aucun descripteur ou autrement accessibles depuis JavaScript. Étant donné que le descripteur de contexte est un descripteur persistant, il n'est pas supprimé lorsque la portée du descripteur est quittée. La seule façon de supprimer le descripteur de contexte est d'appeler explicitement Reset dessus.

Remarque : tout au long de cette page, le terme descripteur fait référence à un descripteur local. Lorsque l'on parle d'un descripteur persistant, ce terme est utilisé dans son intégralité.

Il est important d'être conscient d'un piège courant avec ce modèle  : vous ne pouvez pas renvoyer un descripteur local directement à partir d'une fonction déclarant une portée de descripteur. Si vous le faites, le descripteur local que vous essayez de renvoyer finira par être supprimé par le destructeur de la portée du descripteur immédiatement avant le retour de la fonction. La bonne façon de renvoyer un descripteur local est de construire un EscapableHandleScope au lieu d'un HandleScope et d'appeler la méthode Escape sur la portée du descripteur, en passant le descripteur dont vous souhaitez renvoyer la valeur. Voici un exemple de la façon dont cela fonctionne en pratique :

  1. // Cette fonction renvoie un nouveau tableau avec trois éléments, x, y et z.
  2. Local<Array> NewPointArray(int x, int y, int z) {
  3.   v8::Isolate* isolate = v8::Isolate::GetCurrent();
  4.  
  5.   // Nous créons des descripteurs temporaires, nous utilisons donc une portée de descripteur.
  6.   v8::EscapableHandleScope handle_scope(isolate);
  7.  
  8.   // Créez un nouveau tableau vide.
  9.   v8::Local<v8::Array> array = v8::Array::New(isolate, 3);
  10.  
  11.   // Renvoie un résultat vide s'il y a eu une erreur lors de la création du tableau.
  12.   if (array.IsEmpty())
  13.     return v8::Local<v8::Array>();
  14.  
  15.   // Remplissez les valeurs
  16.   array->Set(0, Integer::New(isolate, x));
  17.   array->Set(1, Integer::New(isolate, y));
  18.   array->Set(2, Integer::New(isolate, z));
  19.  
  20.   // Renvoyer la valeur via Escape.
  21.   return handle_scope.Escape(array);
  22. }

La méthode Escape copie la valeur de son paramètre dans la portée englobante, supprime tous ses descripteurs locaux, puis renvoie la nouvelle copie du descripteur pouvant être renvoyée en toute sécurité.

Contextes

Dans V8, un contexte est un environnement d'exécution permettant à des applications JavaScript distinctes et indépendantes de s'exécuter dans une seule instance de V8. Vous devez spécifier explicitement le contexte dans lequel vous souhaitez que tout code JavaScript soit exécuté.

Pourquoi est-ce nécessaire ? Parce que JavaScript fournit un ensemble de fonctions et d'objets utilitaires intégrés qui peuvent être modifiés par le code JavaScript. Par exemple, si deux fonctions JavaScript entièrement indépendantes modifient toutes deux l'objet global de la même manière, il est assez probable que des résultats inattendus se produisent.

En termes de temps de microprocesseur et de mémoire, il peut sembler coûteux de créer un nouveau contexte d'exécution étant donné le nombre d'objets intégrés qui doivent être créés. Cependant, la mise en cache étendue de V8 garantit que, même si le premier contexte que vous créez est quelque peu coûteux, les contextes suivants sont beaucoup moins chers. Cela est dû au fait que le premier contexte doit créer les objets intégrés et analyser le code JavaScript intégré tandis que les contextes suivants n'ont qu'à créer les objets intégrés pour leur contexte. Avec la fonctionnalité de capture instantanée de V8 (activée avec l'option de construction snapshot=yes, étant la valeur par défaut), le temps passé à créer le premier contexte sera hautement optimisé car une capture instantanée comprend une mémoire de tas sérialisé contenant déjà du code compilé pour le code JavaScript intégré. Outre la récupération de place, la mise en cache étendue de V8 est également essentielle aux performances de V8.

Lorsque vous avez créé un contexte, vous pouvez y entrer et en sortir autant de fois que vous le souhaitez. Lorsque vous êtes dans le contexte A, vous pouvez également entrer dans un contexte différent, B, ce qui signifie que vous remplacez A comme contexte actuel par B. Lorsque vous quittez B, A est restauré comme contexte actuel.

Notez que les fonctions utilitaires intégrées et les objets de chaque contexte sont conservés séparément. Vous pouvez éventuellement définir un jeton de sécurité lorsque vous créez un contexte.

La motivation pour l'utilisation de contextes dans V8 était de permettre à chaque fenêtre et iframe d'un navigateur de disposer de son propre environnement JavaScript.

Gabarits

Un gabarit est un plan directeur pour les fonctions et objets JavaScript dans un contexte. Vous pouvez utiliser un gabarit pour encapsuler des fonctions C++ et des structures de données dans des objets JavaScript afin qu'ils puissent être manipulés par des scripts JavaScript. Par exemple, Google Chrome utilise des gabarits pour encapsuler des noeuds DOM en C++ en tant qu'objets JavaScript et pour installer des fonctions dans l'espace de noms global. Vous pouvez créer un ensemble de gabarits, puis utiliser les mêmes pour chaque nouveau contexte que vous créez. Vous pouvez avoir autant de gabarits que vous le souhaitez. Cependant, vous ne pouvez avoir qu'une seule instance de n'importe quel gabarit dans un contexte donné.

En JavaScript, il existe une forte dualité entre les fonctions et les objets. Pour créer un nouveau type d'objet en Java ou en C++, vous devez généralement définir une nouvelle classe. En JavaScript, vous créez une nouvelle fonction et créez des instances en utilisant la fonction comme constructeur. La disposition et la fonctionnalité d'un objet JavaScript sont étroitement liées à la fonction l'ayant construit. Cela se reflète dans le fonctionnement des gabarits V8. Il existe deux types de gabarits :

Le code suivant fournit un exemple de création d'un gabarit pour l'objet global et de définition des fonctions globales intégrées.

  1. // Créez un gabarit pour l'objet global et définissez les fonctions globales intégrées.
  2. v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
  3. global->Set(v8::String::NewFromUtf8(isolate, "log"),v8::FunctionTemplate::New(isolate, LogCallback));
  4.  
  5. // Chaque processeur dispose de son propre contexte afin que les différents processeurs ne s'affectent pas les uns les autres.
  6. v8::Persistent<v8::Context> context = v8::Context::New(isolate, nullptr, global);

Cet exemple de code est tiré de JsHttpProcessor::Initializer dans l'exemple process.cc.

Accesseurs

Un accesseur est un rappel C++ calculant et renvoyant une valeur lorsqu'une propriété d'objet est accessible par un script JavaScript. Les accesseurs sont configurés via un gabarit d'objet, à l'aide de la méthode SetAccessor. Cette méthode prend le nom de la propriété à laquelle elle est associée et deux rappels à exécuter lorsqu'un script tente de lire ou d'écrire la propriété.

La complexité d'un accesseur dépend du type de données que vous manipulez :

Accéder aux variables globales statiques

Supposons qu'il existe deux variables entières C++, x et y, devant être mises à disposition de JavaScript en tant que variables globales dans un contexte. Pour ce faire, vous devez appeler des fonctions d'accès C++ chaque fois qu'un script lit ou écrit ces variables. Ces fonctions d'accès convertissent un entier C++ en entier JavaScript à l'aide de Integer::New et convertissent un entier JavaScript en entier C++ à l'aide de Int32Value. Un exemple est fourni ci-dessous :

  1. void XGetter(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<Value>& info) {
  2.   info.GetReturnValue().Set(x);
  3. }
  4.  
  5. void XSetter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<void>& info) {
  6.   x = value->Int32Value();
  7. }
  8.  
  9. // YGetter/YSetter sont si similaires qu'ils sont omis par souci de concision
  10.  
  11. v8::Local<v8::ObjectTemplate> global_templ = v8::ObjectTemplate::New(isolate);
  12. global_templ->SetAccessor(v8::String::NewFromUtf8(isolate, "x"), XGetter, XSetter);
  13. global_templ->SetAccessor(v8::String::NewFromUtf8(isolate, "y"), YGetter, YSetter);
  14. v8::Persistent<v8::Context> context = v8::Context::v8::New(isolate, nullptr, global_templ);

Notez que le gabarit d'objet dans le code ci-dessus est créé en même temps que le contexte. Le gabarit aurait pu être créé à l'avance puis utilisé pour n'importe quel nombre de contextes.

Accès aux variables dynamiques

Dans l'exemple précédent, les variables étaient statiques et globales. Que se passe-t-il si les données manipulées sont dynamiques, comme c'est le cas de l'arborescence DOM dans un navigateur ? Imaginons que x et y sont des champs d'objet sur la classe Point de C++  :

  1. class Point {
  2.  public:
  3.   Point(int x, int y) : x_(x), y_(y) { }
  4.   int x_, y_;
  5. }

Pour rendre un nombre quelconque d'instances de points C++ disponibles pour JavaScript, nous devons créer un objet JavaScript pour chaque point C++ et établir une connexion entre l'objet JavaScript et l'instance C++. Cela se fait avec des valeurs externes et des champs d'objet internes.

Créez d'abord un gabarit d'objet pour l'objet d'enveloppe de point :

  1. v8::Local<v8::ObjectTemplate> point_templ = v8::ObjectTemplate::New(isolate);

Chaque objet point JavaScript conserve une référence à l'objet C++ pour lequel il est un enveloppe avec un champ interne. Ces champs sont ainsi nommés car ils ne sont pas accessibles depuis JavaScript, ils ne sont accessibles qu'à partir du code C++. Un objet peut avoir n'importe quel nombre de champs internes, le nombre de champs internes est défini sur le gabarit d'objet comme suit :

  1. point_templ->SetInternalFieldCount(1);

Ici, le nombre de champs internes est défini sur 1, ce qui signifie que l'objet possède un champ interne, avec un index de 0, pointant vers un objet C++.

Ajoutez les accesseurs x et y au gabarit :

  1. point_templ->SetAccessor(v8::String::NewFromUtf8(isolate, "x"), GetPointX, SetPointX);
  2. point_templ->SetAccessor(v8::String::NewFromUtf8(isolate, "y"), GetPointY, SetPointY);

Ensuite, encapsulez un point C++ en créant une nouvelle instance du gabarit, puis en définissant le champ interne 0 sur un wrapper externe autour du point p.

  1. Point* p = ...;
  2. v8::Local<v8::Object> obj = point_templ->NewInstance();
  3. obj->SetInternalField(0, v8::External::New(isolate, p));

L'objet externe est simplement un enveloppe entourant un void*. Les objets externes ne peuvent être utilisés que pour entreposer des valeurs de référence dans des champs internes. Les objets JavaScript ne peuvent pas avoir de références directes à des objets C++, donc la valeur externe est utilisée comme un «pont» pour passer de JavaScript à C++. En ce sens, les valeurs externes sont l'opposé des descripteurs puisque les descripteurs permettent à C++ de faire des références à des objets JavaScript.

Voici la définition des accesseurs get et set pour x, les définitions d'accesseurs y sont identiques sauf que y remplace x :

  1. void GetPointX(Local<String> property, const PropertyCallbackInfo<Value>& info) {
  2.   v8::Local<v8::Object> self = info.Holder();
  3.   v8::Local<v8::External> wrap = v8::Local<v8::External>::Cast(self->GetInternalField(0));
  4.   void* ptr = wrap->Value();
  5.   int value = static_cast<Point*>(ptr)->x_;
  6.   info.GetReturnValue().Set(value);
  7. }
  8.  
  9. void SetPointX(v8::Local<v8::String> property, v8::Local<v8::Value> value,
  10.                const v8::PropertyCallbackInfo<void>& info) {
  11.   v8::Local<v8::Object> self = info.Holder();
  12.   v8::Local<v8::External> wrap = v8::Local<v8::External>::Cast(self->GetInternalField(0));
  13.   void* ptr = wrap->Value();
  14.   static_cast<Point*>(ptr)->x_ = value->Int32Value();
  15. }

Les accesseurs extraient la référence à l'objet point qui a été enveloppé par l'objet JavaScript, puis lisent et écrivent le champ associé. De cette façon, ces accesseurs génériques peuvent être utilisés sur n'importe quel nombre d'objets point enveloppés.

Intercepteurs

Vous pouvez également spécifier un rappel à chaque fois qu'un script accède à une propriété d'objet. Ceux-ci sont appelés intercepteurs. Pour plus d'efficacité, il existe deux types d'intercepteurs :

L'exemple process.cc, fourni avec le code source V8, inclut un exemple d'utilisation d'intercepteurs. Dans l'extrait de code suivant, SetNamedPropertyHandler spécifie les intercepteurs MapGet et MapSet :

  1. v8::Local<v8::ObjectTemplate> result = v8::ObjectTemplate::New(isolate);
  2. result->SetNamedPropertyHandler(MapGet, MapSet);

L'intercepteur MapGet est fourni ci-dessous :

  1. void JsHttpRequestProcessor::MapGet(v8::Local<v8::String> name, const v8::PropertyCallbackInfo<Value>& info) {
  2.   // Récupère la carte enveloppée par cet objet.
  3.   map<string, string> *obj = UnwrapMap(info.Holder());
  4.  
  5.   // Convertissez la chaîne de caractères JavaScript en std::string.
  6.   string key = ObjectToString(name);
  7.  
  8.   // Recherchez la valeur si elle existe en utilisant l'idiome STL standard.
  9.   map<string, string>::iterator iter = obj->find(key);
  10.  
  11.   // Si la clef n'est pas présente, renvoyez un descripteur vide comme signal.
  12.   if (iter == obj->end()) return;
  13.  
  14.   // Sinon, récupérez la valeur et encapsulez-la dans une chaîne de caractères JavaScript.
  15.   const string &value = (*iter).second;
  16.   info.GetReturnValue().Set(v8::String::NewFromUtf8(value.c_str(), v8::String::kNormalString, value.length()));
  17. }

Comme pour les accesseurs, les rappels spécifiés sont invoqués chaque fois qu'une propriété est consultée. La différence entre les accesseurs et les intercepteurs est que les intercepteurs gèrent toutes les propriétés, tandis que les accesseurs sont associés à une propriété spécifique.

Modèle de sécurité

La «politique de même origine» (introduite pour la première fois avec Netscape Navigator 2.0) empêche un document ou un script chargé à partir d'une «origine» d'obtenir ou de définir les propriétés d'un document à partir d'une «origine» différente. Le terme origine est défini ici comme une combinaison de nom de domaine (par exemple www.example.com), de protocole (par exemple https) et de port. Par exemple, www.example.com:81 n'est pas la même origine que www.example.com. Les trois doivent correspondre pour que deux pages Web soient considérées comme ayant la même origine. Sans cette protection, une page Web malveillante pourrait compromettre l'intégrité d'une autre page Web.

Dans V8, une «origine» est définie comme un contexte. L'accès à tout contexte autre que celui à partir duquel vous appelez n'est pas autorisé par défaut. Pour accéder à un contexte autre que celui à partir duquel vous appelez, vous devez utiliser des jetons de sécurité ou des rappels de sécurité. Un jeton de sécurité peut être n'importe quelle valeur, mais il s'agit généralement d'un symbole, une chaîne de caractères canonique n'existant nulle part ailleurs. Vous pouvez éventuellement spécifier un jeton de sécurité avec SetSecurityToken lorsque vous configurez un contexte. Si vous ne spécifiez pas de jeton de sécurité, V8 en génère automatiquement un pour le contexte que vous créez.

Lorsqu'une tentative d'accès à une variable globale est effectuée, le système de sécurité V8 vérifie d'abord le jeton de sécurité de l'objet global auquel vous accédez par rapport au jeton de sécurité du code qui tente d'accéder à l'objet global. Si les jetons correspondent, l'accès est accordé. Si les jetons ne correspondent pas, V8 effectue un rappel pour vérifier si l'accès doit être autorisé. Vous pouvez spécifier si l'accès à un objet doit être autorisé en définissant le rappel de sécurité sur l'objet, à l'aide de la méthode SetAccessCheckCallbacks sur les modèles d'objet. Le système de sécurité V8 peut ensuite récupérer le rappel de sécurité de l'objet auquel vous accédez et l'appeler pour demander si un autre contexte est autorisé à y accéder. Ce rappel reçoit l'objet auquel on accède, le nom de la propriété à laquelle on accède, le type d'accès (lecture, écriture ou suppression par exemple) et renvoie s'il faut ou non autoriser l'accès.

Ce mécanisme est implémenté dans Google Chrome de sorte que si les jetons de sécurité ne correspondent pas, un rappel spécial est utilisé pour autoriser l'accès uniquement aux éléments suivants : window.focus(), window.blur(), window.close(), window.location, window.open(), history.forward(), history.back() et history.go().

Exceptions

V8 génère une exception si une erreur se produit, par exemple lorsqu'un script ou une fonction tente de lire une propriété n'existant pas, ou si une fonction est appelée n'étant pas une fonction.

V8 renvoie un descripteur vide si une opération n'a pas réussi. Il est donc important que votre code vérifie qu'une valeur de retour n'est pas un descripteur vide avant de poursuivre l'exécution. Vérifiez s'il y a un descripteur vide avec la fonction membre publique IsEmpty() de la classe Local.

Vous pouvez intercepter les exceptions avec TryCatch, par exemple :

  1. v8::TryCatch trycatch(isolate);
  2. v8::Local<v8::Value> v = script->Run();
  3. if (v.IsEmpty()) {
  4.   v8::Local<v8::Value> exception = trycatch.Exception();
  5.   v8::String::Utf8Value exception_str(exception);
  6.   printf("Exception: %s\n", *exception_str);
  7.   // ...
  8. }

Si la valeur renvoyée est un descripteur vide et que vous n'avez pas de TryCatch en place, votre code doit abandonner. Si vous avez un TryCatch, l'exception est interceptée et votre code est autorisé à poursuivre le traitement.

Héritage

JavaScript est un langage orienté objet sans classe et, en tant que tel, il utilise l'héritage prototypique au lieu de l'héritage classique. Cela peut être déroutant pour les programmeurs formés aux langages orientés objet conventionnels comme C++ et Java.

Les langages orientés objet basés sur les classes, tels que Java et C++, sont fondés sur le concept de deux entités distinctes : les classes et les instances. JavaScript est un langage basé sur des prototypes et ne fait donc pas cette distinction : il contient simplement des objets. JavaScript ne prend pas en charge nativement la déclaration de hiérarchies de classes ; cependant, le mécanisme de prototype de JavaScript simplifie le processus d'ajout de propriétés et de méthodes personnalisées à toutes les instances d'un objet. En JavaScript, vous pouvez ajouter des propriétés personnalisées aux objets. Par exemple :

  1. // Créez un objet nommé «bicycle».
  2. function bicycle() {}
  3. // Créez une instance de «bicycle» appelée «roadbike».
  4. var roadbike = new bicycle();
  5. // Définissez une propriété personnalisée, «wheels», sur «roadbike».
  6. roadbike.wheels = 2;

Une propriété personnalisée ajoutée de cette manière n'existe que pour cette instance de l'objet. Si nous créons une autre instance de bicycle(), appelée mountainbike par exemple, mountainbike.wheels renverrait undefined à moins que la propriété wheels ne soit explicitement ajoutée.

Parfois, c'est exactement ce qui est requis, à d'autres moments, il serait utile d'ajouter la propriété personnalisée à toutes les instances d'un objet - après tout, tous les vélos ont des roues. C'est là que l'objet prototype de JavaScript est très utile. Pour utiliser l'objet prototype, référencez le mot-clef prototype sur l'objet avant d'y ajouter la propriété personnalisée comme suit :

  1. // Tout d'abord, créez l'objet «bicycle»
  2. function bicycle() {}
  3. // Affecter la propriété des roues au prototype de l'objet
  4. bicycle.prototype.wheels = 2;

Toutes les instances de bicycle() auront désormais la propriété wheels pré-intégrée.

La même approche est utilisée dans V8 avec les gabarits. Chaque FunctionTemplate possède une méthode PrototypeTemplate fournissant un gabarit pour le prototype de la fonction. Vous pouvez définir des propriétés et associer des fonctions C++ à ces propriétés sur un PrototypeTemplate étant alors présent sur toutes les instances du FunctionTemplate correspondant. Par exemple :

  1. v8::Local<v8::FunctionTemplate> biketemplate = v8::FunctionTemplate::New(isolate);
  2. biketemplate->PrototypeTemplate().Set(
  3.     v8::String::NewFromUtf8(isolate, "wheels"),
  4.     v8::FunctionTemplate::New(isolate, MyWheelsMethodCallback)->GetFunction()
  5. );

Cela fait que toutes les instances de biketemplate ont une méthode wheels dans leur chaîne de prototypes qui, lorsqu'elle est appelée, provoque l'appel de la fonction MyWheelsMethodCallback de C++.

La classe FunctionTemplate de V8 fournit la fonction membre publique Inherit() que vous pouvez appeler lorsque vous souhaitez qu'un modèle de fonction hérite d'un autre modèle de fonction, comme suit :

  1. void Inherit(v8::Local<v8::FunctionTemplate> parent);    


Dernière mise à jour : Jeudi, le 19 septembre 2024