Chinaunix首页 | 论坛 | 博客
  • 博客访问: 642776
  • 博文数量: 133
  • 博客积分: 1566
  • 博客等级: 上尉
  • 技术积分: 1230
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-01 09:31
文章分类

全部博文(133)

文章存档

2019年(1)

2018年(1)

2017年(8)

2016年(9)

2015年(17)

2014年(4)

2013年(31)

2012年(25)

2011年(36)

2010年(1)

我的朋友

分类: Windows平台

2017-03-09 14:43:21

1. 脚本引擎的基本功能

V8只是一个JS引擎。去除它的特点功能出处,它必须要实现JS引擎的几个基础功能:

  • 脚本执行:
    • 脚本可能是一个表达式;一段js代码;或者一个文件
    • 执行表达式返回js表达式对应的值
  • C++来取设JS的内容
    • 获取JS内容的数据(包括基础数据类型、数组、日期等)、对象(类的一个实例)、类或函数
    • 设置JS内容的数据
  • JS来取设C++的内容
    • C++为js动态添加类(例如:Date,可以通过new Date()来创建任意多个对象)
    • C++为js动态添加全局对象(例如:Math,可以直接调用其全局方法如Math.min)

我们的目的是先学会怎么用,再去想为什么!

2. V8 脚本引擎基本功能实现

带着这几个目的去使用V8,找遍网上资料,发现很少有覆盖周全的。其实翻来覆去就是那几个资料,理论派居多;最可气的是按照那些例子去跑,怎么都会运行错误;而且在关键的地方全按照google伪代码例子照搬。不过理论派的阐述确实很一本正经;很精辟。也感谢先行者!

2. 1 V8之脚本运行

2.1.1 获取字符串:

点击(此处)折叠或打开

  1. void test_String()
  2. {
  3.     Handle<String> source = String::New("'Hello' + ', World!'");
  4.     Handle<Script> script = Script::Compile(source);
  5.     Handle<Value> result = script->Run();

  6.     String::AsciiValue ascii(result);
  7.     printf("%s\n", *ascii);
  8. }
  9. >>> Hello,World!

2.1.2 获取数组:

点击(此处)折叠或打开

  1. void test_Array()
  2. {
  3.     Handle<String> source = String::New("[1, 2, 'hello', 6+5]");
  4.     Handle<Script> script = Script::Compile(source);
  5.     Handle<Value> result = script->Run();

  6.     String::AsciiValue ascii(result);
  7.     printf("%s\n", *ascii);
  8. }
  9. >>> 1,2,hello,11

2. 2 V8之C++取设JS

2.2.1 获取成员之数据

点击(此处)折叠或打开

  1. void test_getjs_data(Handle<Context> pContext)
  2. {
  3.     Handle<String> source = String::New("var s1 = 8+5;");
  4.     Handle<Script> script = Script::Compile(source);
  5.     Handle<Value> result = script->Run();
  6.     Handle<String> js_data = String::New("s1");
  7.     Handle<Value> js_data_value = pContext->Global()->Get(js_data);

  8.     String::AsciiValue ascii(js_data_value);
  9.     printf("%s\n", *ascii);
  10. }
  11. >>> 13
2.2.2 获取成员之全局对象

点击(此处)折叠或打开

  1. void test_getjs_dataofObject(Handle<Context> pContext)
  2. {
  3.     Handle<String> source = String::New("function Point(x,y){this.x=x; this.y=y;} var pt=new Point(10,20);");
  4.     Handle<Script> script = Script::Compile(source);
  5.     Handle<Value> result = script->Run();

  6.     Handle<String> js_data = String::New("pt");
  7.     Handle<Value> js_data_value = pContext->Global()->Get(js_data);

  8.     // Convert the result to an ASCII string and print it.
  9.     {
  10.         String::AsciiValue ascii(js_data_value);
  11.         printf("pt = %s\n", *ascii);
  12.     }
  13.     Handle<Object> js_data_object = Handle<Object>::Cast(js_data_value);

  14.     Handle<Value> key = String::New("x");
  15.     Handle<Value> objX = js_data_object->Get(key);
  16.     {
  17.         String::AsciiValue ascii(objX);
  18.         printf("pt.x = %s\n", *ascii);
  19.     }
  20. }
  21. >>> pt = [object Object]
  22. pt.x = 10
2.2.3 获取js 类

点击(此处)折叠或打开

  1. void test_getjs_dataofObjectClass(Handle<Context> pContext)
  2. {
  3.     Handle<String> source = String::New("function Point(x,y){this.x=x; this.y=y;} Point.prototype.show=function(){return '(x,y) = '+this.x+','+this.y;}");
  4.     Handle<Script> script = Script::Compile(source);
  5.     Handle<Value> result = script->Run();

  6.     Handle<String> js_data = String::New("Point");
  7.     Handle<Value> js_data_value = pContext->Global()->Get(js_data);

  8.     // Convert the result to an ASCII string and print it.
  9.     {
  10.         String::AsciiValue ascii(js_data_value);
  11.         printf("Point = %s\n", *ascii);
  12.     }

  13.     bool bIsFunction = js_data_value->IsFunction();
  14.     if(bIsFunction)
  15.     {
  16.         printf("Point is function\n");
  17.     }

  18.     bool bIsObject = js_data_value->IsObject();
  19.     if(bIsObject)
  20.     {
  21.         printf("Point is object\n");
  22.     }

  23.     Handle<Object> js_data_object = Handle<Object>::Cast(js_data_value);
  24.     // var newObj = new Point(1,2);
  25.     Handle<Value> argv[2] ;
  26.     argv[0] = Int32::New(1);
  27.     argv[1] = Int32::New(2);
  28.     Handle<Value> newObj = js_data_object->CallAsConstructor(2, argv);
  29.     {
  30.         bool bIsFunction = newObj->IsFunction();
  31.         if(bIsFunction) //-false-
  32.         {
  33.             printf("newObj is function\n");
  34.         }

  35.         bool bIsObject = newObj->IsObject();
  36.         if(bIsObject) //-true-
  37.         {
  38.             printf("newObj is object\n");
  39.         }
  40.     }

  41.     // newObj.show();
  42.     {
  43.         Handle<Object> obj = Handle<Object>::Cast(newObj);
  44.         Handle<String> js_func_name = String::New("show");
  45.         Handle<Value> js_func_ref = obj->Get(js_func_name);

  46.         Handle<Function> js_func = Handle<Function>::Cast(js_func_ref);
  47.         js_data_value = js_func->Call(obj, 0, NULL) ;

  48.         String::AsciiValue ascii(js_data_value);
  49.         printf("newObj.show() = %s\n", *ascii);
  50.     }
  51. }
  52. >>> Point = function Point(x,y){this.x=x; this.y=y;}
  53. Point is function
  54. Point is object
  55. newObj is object
  56. newObj.show() = (x,y) = 1,2

2. 3 V8之JS取设C++

2.3.0 js 和 C++的关联

c++ 和 js对应。特别是为达到能在Js中使用var obj = new CObject(),参照CreateObjectToJs方法

点击(此处)折叠或打开

  1. void test_getc_loadObjectTemplate(Handle<ObjectTemplate> pObj)
  2. {
  3.     //-load c++'s data-
  4.     pObj->SetAccessor(String::New("x"), XGetter, XSetter);

  5.     //-load c++'s function-
  6.     pObj->Set(String::New("setColor"),FunctionTemplate::New(set_color));

  7.     //-load c++'s class-
  8.     CreateObjectToJs(pObj);
  9. }


  10. Point* NewPointFunction(const Arguments & args)
  11. {
  12.     if(args.Length()==2)
  13.     {
  14.         Local<Value> v1 = args[0];
  15.         Local<Value> v2 = args[1];

  16.         return new Point( v1->Int32Value(), v2->Int32Value() );
  17.     }
  18.     else
  19.         return new Point();
  20. }

  21. void PointWeakExternalReferenceCallback(Persistent<Value>, void* parameter)
  22. {
  23.     if (Point* cpp_object = static_cast<Point*>(parameter))
  24.         delete cpp_object;
  25. }

  26. Persistent<External> NewWeakExternalPoint(void* parameter)
  27. {
  28.     Persistent<External> ret = Persistent<External>::New(External::New(parameter));
  29.     ret.MakeWeak(parameter, PointWeakExternalReferenceCallback);
  30.     return ret;
  31. }

  32. Handle<Value> PointFunctionInvocationCallback(const Arguments &args)
  33. {
  34.     if (!args.IsConstructCall())
  35.         return Undefined();

  36.     Point* cpp_object = NewPointFunction(args);
  37.     if (!cpp_object)
  38.         return ThrowException(String::New("Can not create Object in C++"));

  39.     args.Holder()->SetInternalField(0, NewWeakExternalPoint(cpp_object));
  40.     return Undefined();
  41. }


  42. void CreateObjectToJs(Handle<ObjectTemplate> pObj)
  43. {
  44.     Point* p = new Point(0, 0);
  45.     Handle<FunctionTemplate> point_templ = FunctionTemplate::New(&PointFunctionInvocationCallback, External::New(p));
  46.     point_templ->SetClassName(String::New("Point"));
  47.     point_templ->InstanceTemplate()->SetInternalFieldCount(1);

  48.     Handle<ObjectTemplate> point_proto = point_templ->PrototypeTemplate();
  49.     point_proto->SetAccessor(String::New("x"), GetPointX, SetPointX);
  50.     point_proto->SetAccessor(String::New("y"), GetPointY, SetPointY);
  51.     point_proto->Set(String::New("show"), FunctionTemplate::New(ShowPoint));

  52.     pObj->Set(String::New("Point"), point_templ);
  53. }

2.3.1 全局函数

c++: 

点击(此处)折叠或打开

  1. Handle<Value> set_color(const Arguments & args)
  2. {
  3.     Handle<Value> rtn;
  4.     if(args.Length() == 3)
  5.     {
  6.         int r = args[0]->Int32Value();
  7.         int g = args[1]->Int32Value();
  8.         int b = args[2]->Int32Value();

  9.         char szTmp[80] = "";
  10.         _stprintf(szTmp,"RGB%2X%02X%02X", r,g,b);
  11.         rtn = String::New(szTmp);
  12.     }
  13.     else
  14.         rtn = Undefined();

  15.     return rtn;
  16. }

JS:

点击(此处)折叠或打开

  1. void test_getc_function(Handle<Context> pContext, Handle<ObjectTemplate> pObj)
  2. {
  3.     Handle<String> source = String::New("var data = setColor(255,128,0);");
  4.     Handle<Script> script = Script::Compile(source);
  5.     Handle<Value> result = script->Run();

  6.     Handle<String> js_data = String::New("data");
  7.     Handle<Value> js_data_value = pContext->Global()->Get(js_data);

  8.     // Convert the result to an ASCII string and print it.
  9.     String::AsciiValue ascii(js_data_value);
  10.     printf("%s\n", *ascii);
  11. }
  12. >>> RGBFF8000

2.3.2 全局数据

c++:

点击(此处)折叠或打开

  1. int x = 0;
  2. Handle<Value> XGetter(Local<String> key,const AccessorInfo& info)
  3. {
  4.     return Integer::New(x);
  5. }

  6. void XSetter(Local<String> key, Local<Value> value,const AccessorInfo& info)
  7. {
  8.     x = value->Int32Value();
  9. }
JS:

点击(此处)折叠或打开

  1. void test_getc_data(Handle<Context> pContext, Handle<ObjectTemplate> pObj)
  2. {
  3.     Handle<String> source = String::New("var data1 = x; x=200; var data2=x;");
  4.     Handle<Script> script = Script::Compile(source);
  5.     Handle<Value> result = script->Run();

  6.     {
  7.         Handle<String> js_data = String::New("data1");
  8.         Handle<Value> js_data_value = pContext->Global()->Get(js_data);
  9.         String::AsciiValue ascii(js_data_value);
  10.         printf("data1 = %s\n", *ascii);
  11.     }

  12.     {
  13.         Handle<String> js_data = String::New("data2");
  14.         Handle<Value> js_data_value = pContext->Global()->Get(js_data);
  15.         String::AsciiValue ascii(js_data_value);
  16.         printf("data2 = %s\n", *ascii);
  17.     }
  18. }
  19. >>> data1 = 0
  20. data2 = 200

2.3.3 类

c++:

点击(此处)折叠或打开

  1. struct Point
  2. {
  3.     Point()
  4.     {
  5.         x_ = 0;
  6.         y_ = 0;
  7.     }
  8.     Point(int x, int y)
  9.     {
  10.         x_ = x;
  11.         y_ = y;
  12.     }

  13.     int getX() const {
  14.         return x_;
  15.     }
  16.     int getY() const { return y_; }
  17.     void setX(int value) { x_ = value; }
  18.     void setY(int value) { y_ = value; }
  19.     bool isNull() const { return x_ == 0 && y_ == 0; }
  20.     void show()
  21.     {
  22.         char szTmp[80] = "";
  23.         _stprintf(szTmp, "x,y = %d,%d\n", x_, y_);
  24.         printf(szTmp);
  25.     }
  26.     int x_, y_;
  27. };


  28. Handle<Value> GetPointX(Local<String> key,const AccessorInfo &info)
  29. {
  30.     Handle<Object> obj = info.This ();
  31.     //Local<Object> self = info.Holder(); //
  32.     Point& point = *static_cast<Point*> (Local<External>::Cast(obj->GetInternalField(0))->Value ());
  33.     int value = point.x_;
  34.     return Integer::New(value);
  35. }

  36. void SetPointX(Local<String> key, Local<Value> value,const AccessorInfo& info)
  37. {
  38.     Handle<Object> obj = info.This ();
  39.     Point& point = *static_cast<Point*> (Local<External>::Cast(obj->GetInternalField(0))->Value ());
  40.     point.x_ = value->Int32Value();
  41. }

  42. Handle<Value> GetPointY(Local<String> key,const AccessorInfo &info)
  43. {
  44.     Local<Object> self = info.Holder();
  45.     Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));
  46.     void* ptr = wrap->Value();
  47.     int value = static_cast<Point*>(ptr)->y_;
  48.     return Integer::New(value);
  49. }

  50. void SetPointY(Local<String> key, Local<Value> value,const AccessorInfo& info)
  51. {
  52.     Local<Object> self = info.Holder();
  53.     Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));
  54.     void* ptr = wrap->Value();
  55.     static_cast<Point*>(ptr)->y_ = value->Int32Value();
  56. }

  57. Handle<Value> ShowPoint(const Arguments& args)
  58. {
  59.     Local<Object> self = args.Holder();
  60.     //Local<Object> self = info.Holder();
  61.     Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));
  62.     void* ptr = wrap->Value();
  63.     static_cast<Point*>(ptr)->show();

  64.     return Undefined();
  65. }
JS:

点击(此处)折叠或打开

  1. void test_getc_object(Handle<Context> pContext, Handle<ObjectTemplate> pObj)
  2. {
  3.     test_getobject(pContext);return;

  4.     // Create a string containing the JavaScript source code.
  5.     Handle<String> source = String::New("var pt=new Point(10,20);");

  6.     // Compile the source code.
  7.     Handle<Script> script = Script::Compile(source);

  8.     // Run the script to get the result.
  9.     Handle<Value> result = script->Run();

  10.     Handle<String> js_data = String::New("pt");
  11.     Handle<Value> js_data_value = pContext->Global()->Get(js_data);

  12.     // Convert the result to an ASCII string and print it.
  13.     {
  14.         String::AsciiValue ascii(js_data_value);
  15.         printf("pt = %s\n", *ascii);
  16.     }

  17.     Handle<Object> js_data_object = Handle<Object>::Cast(js_data_value);

  18.     Handle<Value> key = String::New("x");
  19.     Handle<Value> objX = js_data_object->Get(key);
  20.     {
  21.         String::AsciiValue ascii(objX);
  22.         printf("pt.x = %s\n", *ascii);
  23.     }
  24. }
  25. >>> Point = function Point() { [native code] }
  26. Point is function
  27. Point is object
  28. newObj is object
  29. src obj.= 3
  30. last obj.= 30
  31. begin newObj.show() : x,= 30,4
  32. newObj.show() = undefined

3. 教训

  • 在VS200X C++中,请都使用/MDD 编译选项
  • 对于类,需要绑定一个构造函数,主要目的是用来生成C++对象。该对象千万不要使用局部变量,而要是指针
  • 对于C++扩展的类,通过FunctionTemplate来实现;而不要使用ObjectTemplate
  • 对于JS中的全局对象,可以通过ObjectTemplate来实现。实际上就是绑定全局API和变量





阅读(4437) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~