javascript引擎在c,c+中调用

JavaScript是一种广泛用于Web客户端开发的脚本语言,常用来控制浏览器的DOM树,给HTML网页添加动态功能。目前JavaScript遵循的web标准的是ECMAScript262。由于JavaScript提供了丰富的内置函数、良好的对象机制。所以JavaScript还可以嵌入到某一种宿主语言中,弥补宿主语言的表现力,从而实现快速、灵活、可定制的开发。
软件程序应用javascript
现有的主流浏览器基本上都实现了一个自己的JavaScript引擎。这些JavaScript引擎可以分析、编译和执行JavaScript脚本。这些JavaScript引擎都是用C或者C++语言写的,都对外提供了API接口。所以在C、C++语言中使用这些JavaScript引擎,嵌入JavaScript是非常方便的。有一些著名的开源项目都使用了这一种方式,来进行混合的编程,比如Node.js, K-3D等。

已知著名的JavaScript引擎有Google的V8引擎、IE的Trident引擎、Firefox的SpiderMonkey引擎、Webkit的JavaScriptCore引擎、Opera的Carakan引擎(非开源的,本文没有分析)等。这些JavaScript引擎对外提供的API接口在细节上各不相同,但是这些API的一个基本的设计思路都类似。C、C++要使用这些引擎,首先要获得一个全局的Global对象。这个全局的Global对象有属性、方法、事件。比如在JavaScript环境中有一个window窗口对象。它描述的是一个浏览器窗口。一般JavaScript要引用它的属性和方法时,不需要用“window.xxx”这种形式,而直接使用“xxx”。 它是JavaScript中最大的对象,所有的其他JavaScript对象、函数或者是它的子对象,或者是子对象的子对象。C、C++通过对这个最大的Global对象调用get、set操作就可以实现与JavaScript进行双向交互了。
V8对外的API接口是C++的接口。V8的API定义了几个基本概念:句柄(handle),作用域(scope),上下文环境(Context)。模板(Templates),了解这些基本的概念才可以使用V8。

l 上下文环境Context就是脚本的运行环境,JavaScript的变量、函数等都存在于上下文环境Context中。Context可以嵌套,即当前函数有一个Context,调用其它函数时如果又有一个Context,则在被调用的函数中javascript是以最近的Context为准的,当退出这个函数时,又恢复到了原来的Context。

l 句柄(handle)就是一个指向V8对象的指针,有点像C++的智能指针。所有的v8对象必须使用句柄来操作。没有句柄指向的V8对象,很快会被垃圾回收器回收了。

l 作用域(scope)是句柄的容器,一个作用域(scope)可以有很多句柄(handle)。当离开一个作用域(scope)时,所有在作用域(scope)里的句柄(handle)都会被释放了。

l 模板(Templates)分为函数模板和对象模板,是V8对JavaScript的函数和对象的封装。方便C++语言操作JavaScript的函数和对象。

l V8 API定义了一组类或者模板,用来与JavaScript的语言概念一一对应。比如:

V8的 Function模板与JavaScript的函数对应

V8的Object类与JavaScript的对象对应

V8的String类与JavaScript的字符对应

V8的Script类与JavaScript的脚本文本对应,它可以编译并执行一段脚本。

2.2. C++调用JavaScript

使用V8,在C++中访问Javascript脚本中的内容,首先要调用Context::GetCurrent()->Global()获取到Global全局对象,再通过Global全局对象的Get函数来提取Javascript的全局变量、全局函数、全局复杂对象。C++代码示例如下:

//获取Global对象

HandleglobalObj = Context::GetCurrent()->Global();

//获取Javascrip全局变量

Handle value = globalObj->Get(String::New(“JavaScript变量名”));

intn = value ->ToInt32()->Value();

//获取Javascrip全局函数,并调用全局函数

Handle value = globalObj->Get(String::New(“JavaScript函数名”));

Handle func = Handle ::Cast(value) ;//转换为函数

Local v1 = Int32::New(0);

Local<Value> v2 = Int32::New(1);

Handle args[2] = { v1, v2 }; //函数参数

func->Call(globalObj, 2, args);

//获取Javascrip全局对象,并调用对象的函数

Handle value = globalObj->Get(String::New(“JavaScript复杂对象名”));

Handle obj = Handle::Cast(value);//转换为复杂对象

Handle objFunc = obj ->Get(String::New(“JavaScript对象函数名”));

Handle args[] = {String::New(“callobject function “)};//函数参数

objFunc->Call(globalObj, 1, args);

2.3. JavaScript调用C++

使用V8,在Javascript脚本中想要访问C++中的内容,必须先将C++的变量、函数、类注入到Javacsript中。注入时,首先要调用Context::GetCurrent()->Global()获取到Global对象,再通过Global对象的Set函数来注入全局变量、全局函数、类对象。

全局变量、全局函数的注入过程与上一节的代码类似,这里就省略不写了。比较麻烦的是将C++的类、类对象注入到Javascript中。其基本的过程如下:

  1. 首先定义一个C++类,定义一个类对象指针
  2. 定义一组C++全局函数,封装V8对C++类的调用,提供给V8进行CALLBACK回调。
  3. 最后调用V8 API,将定义的C++类和C++函数注入到Javascript中

在V8的API接口中,还提供了一个“内部数据”(Internal Field)的概念,“内部数据”就是允许V8对象保存一个C++的void指针。当V8回调C++全局函数时,C++可以设置或者获取该void指针。

下面是一个将C++类、类变量注入到Javascript中的C++代码示例。

//一个C++类test、

class test

{

public:

test(){number=0;};

voidfunc(){number++;}

int number;

};

//一个全局对象g_test

//目的是:在Javascript中可以直接使用这个对象,例如g_test.func()

test g_test;

//封装V8调用test类构造函数

//在Javascript中如果执行:var t = new test;V8就会调用这个C++函数

//在C++中执行NewInstance函数注入对象时,也会调用这个函数

//默认的test类的构造函数没有参数,C++注入对象时,提供一个额外的参数

v8::Handle testConstructor(constv8::Arguments& args)

{

v8::Local<v8::Object>self = args.Holder();

//这里假定有两个“内部数据”(Internal Field)

//第一个“内部数据”保存test对象的指针

//第二个“内部数据”为1 就表示这个对象是由C++注入的

//第二个“内部数据”为0 就表示这个对象是JS中自己建立的

if(args.Length())

{

    //默认为0,当C++注入对象时,会填充这个“内部数据”

    self->SetInternalField(0,v8::External::New(0));

    self->SetInternalField(1,v8::Int32::New(1));

}

else

{

    self->SetInternalField(0,v8::External::New(new test));

    self->SetInternalField(1,v8::Int32::New(0));

}

return self;

}

//封装V8调用test类func方法

//在Javascript中如果执行:t.func();V8就会调用这个C++函数

v8::Handle testFunc(constv8::Arguments& args)

{

//获取构造函数testConstructor时,设置的对象指针

v8::Local<v8::Object>self = args.Holder();

v8::Local wrap =v8::Local ::Cast(self->GetInternalField(0));

void* ptr =wrap->Value();

//调用类方法

static_cast<test*>(ptr)->func();

returnv8::Undefined();

}

//封装V8调用test类成员变量number

//在Javascript中如果执行:t.number;V8就会调用这个C++函数

v8::Handle getTestNumber(v8::Local property, const v8::AccessorInfo& info)

{

//获取构造函数testConstructor时,设置的对象指针

v8::Local<v8::Object>self = info.Holder();

v8::Local wrap =v8::Local ::Cast(self->GetInternalField(0));

void* ptr =wrap->Value();

//返回类变量

returnv8::Int32::New(static_cast<test*>(ptr)->number);

}

//C++类和全局的函数定义好以后,就可以开始将类、变量注入V8 Javascript中了

//获取global对象

v8::Handle globalObj =context->Global();

//新建一个函数模板,testConstructor是上面定义的全局函数

v8::Handle test_templ =v8::FunctionTemplate::New(testConstructor);

//设置类名称

test_templ->SetClassName(v8::String::New(“test”));

//获取Prototype,

v8::Handle test_proto =test_templ->PrototypeTemplate();

//增加类成员函数,testFunc是上面定义的全局函数

test_proto->Set(“func”,v8::FunctionTemplate::New(testFunc));

//设置两个内部数据,用于构造函数testConstructor时,存放类对象的指针。

v8::Handle test_inst =test_templ->InstanceTemplate();

test_inst->SetInternalFieldCount(2)

//增加类成员变量

//getTestNumber是上面定义的全局函数

//只提供了成员变量的get操作,最后一个参数是成员变量的set操作,这里省略了

test_inst->SetAccessor(v8::String::New(“number”),getTestNumber, 0);

//将test类的定义注入到Javascript中

v8::Handle point_ctor =test_templ->GetFunction();

globalObj->Set(v8::String::New(“test”),point_ctor);

//新建一个test对象,并使得g_test绑定新建的对象

v8::Handle flag = v8::Int32::New(1);

v8::Handle obj =point_ctor->NewInstance(1, &flag);

obj->SetInternalField(0, v8::External::New(&g_test));

globalObj->Set(v8::String::New(“g_test”), obj);

将C++类和类指针注入到V8 JavaScript后,在JavaScript中就可以这样使用了:

g_test.func();

var n = g_test.number;

var t = new test;
end.

时间: 2024-10-12 04:42:26

javascript引擎在c,c+中调用的相关文章

在C#中调用VBScript和JavaScript等脚本的实现

在C#中调用VBScript.JavaScript等脚本的实现 作者:郑佐 2004-04-26 以前在做工作流(workflow)项目的时候,里面有一项就是在用户制定流程定义时可以编写脚本来控制活动的跳转,而这些脚本定义后存在数据库中,当流程启动的时候,工作流引擎会控制活动执行顺序,串型的两个活动比较简单,但有的活动到下一个活动有条件判断,或者存在多个分支,简单的还好,只要在数据库表中加个字段就可以实现,复杂一点的就需要通过脚本实现了.当时经验不够,几天都没找到快速的解决办法,想自己写一个自定

JavaScript是如何工作的01:引擎,运行时和调用堆栈的概述!

概述 几乎每个人都已经听说过 V8 引擎,大多数人都知道 JavaScript 是单线程的,或者它使用的是回调队列. 在本文中,我们将详细介绍这些概念,并解释 JavaScrip 实际如何运行.通过了解这些细节,你将能够适当地利用所提供的 API 来编写更好的.非阻塞的应用程序. 如果您对JavaScript还比较陌生,那么本文将帮助您理解为什么JavaScript与其他语言相比如此“怪异”. 如果你是一个有经验的JavaScript开发人员,希望它能让您对每天使用的JavaScript运行时的

在 Flash ActionScript 2.0 中调用 Javascript 方法

本篇文章由:http://xinpure.com/call-the-javascript-method-in-flash-actionscript-2-0/ 在 Flash ActionScript 2.0 中调用 Javascript 方法 最近在工作中,有个这样的需求: 要从 Flash ActionScript 2.0 中调用网页上的 Javascript 方法 这是一个关于 Flash 和 Javascript 交互的问题. 在 ActionScript 2.0 中调用外部 javasc

JDK1.7中调用javascript方法

import java.io.File; import javax.script.Invocable; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; public class TestJs { public static void main(String[] args) throws Exception { Script

Effective JavaScript Item 38 在子类构造函数中调用父类构造函数

本系列作为Effective JavaScript的读书笔记. 在一个游戏或者图形模拟的应用中,都会有场景(Scene)这一概念.在一个场景中会包含一个对象集合,这些对象被称为角色(Actor).而每个角色根据其类型会有一个图像用来表示,同时场景也需要保存一个底层图形展示对象的引用,被称为上下文(Context): function Scene(context, width, height, images) { this.context = context; this.width = width

C#中调用javascript

结合网上的代码整理了一下c#中调用js的方法,仅用于留存. ps.测试用的js文件需要放到bin\Debug下 代码如下: using System; using System.IO; namespace CallJSTest { class Program { static void Main(string[] args) { CallJs(); } private static void CallJs() { string path = AppDomain.CurrentDomain.Bas

使用Edge.js,在JavaScript中调用C# .Net

Edge.js能够让开发者在JavaScript中调用C#的接口,提高应用的扩展能力.这里介绍如何调用C#接口获取图片数据,并通过Node.js搭建的WebSocket server发送到Web客户端. 参考:How to Use Edge.js to Empower WebSocket Solutions in JavaScript 通过.Net接口获取图片返回给JavaScript 先看下单纯使用JavaScript来load本地图片可以这样: var fs = require('fs');

Javascript引擎单线程机制及setTimeout执行原理说明

setTimeout用法在实际项目中还是会时常遇到.比如浏览器会聪明的等到一个函数堆栈结束后才改变DOM,如果再这个函数堆栈中把页面背景先从白色设为红色,再设回白色,那么浏览器会认为DOM没有发生任何改变而忽略这两句话,因此我们可以通过setTimeout把“设回白色”函数加入下一个堆栈,那么就可以确保背景颜色发生过改变了(虽然速度很快可能无法被察觉). 总之,setTimeout增加了Javascript函数调用的灵活性,为函数执行顺序的调度提供极大便利. 然后,我们从基础的层面来看看:理解J

javascript引擎工作原理

1. 什么是JavaScript解析引擎? 简单地说,JavaScript解析引擎就是能够“读懂”JavaScript代码,并准确地给出代码运行结果的一段程序.比方说,当你写了 var a = 1 + 1; 这样一段代码,JavaScript引擎做的事情就是看懂(解析)你这段代码,并且将a的值变为2. 学过编译原理的人都知道,对于静态语言来说(如Java.C++.C),处理上述这些事情的叫编译器(Compiler),相应地对于JavaScript这样的动态语言则叫解释器(Interpreter)