99热99这里只有精品6国产,亚洲中文字幕在线天天更新,在线观看亚洲精品国产福利片 ,久久久久综合网

歡迎加入QQ討論群258996829
麥子學(xué)院 頭像
蘋果6袋
6
麥子學(xué)院

Node.js 和 C++ 之間的類型轉(zhuǎn)換

發(fā)布時間:2017-01-05 16:33  回復(fù):0  查看:2703   最后回復(fù):2017-01-05 16:33  

我非常喜歡使用 Node.js開發(fā),但是當(dāng)涉及到計算密集型的場景時 Node.js 就不能夠很好地勝任了。而在這樣的情況下 C++ 是一個很好的選擇,非常幸運 Node.js 官方提供了C/C++ Addons 的機(jī)制讓我們能夠使用 V8 API Node.js C++ 結(jié)合起來。

  雖然在 Node.js 官方網(wǎng)站有很多的關(guān)于怎么使用這些 API 的文檔,但是在 JavaScript C++ 之間傳遞數(shù)據(jù)是一件非常麻煩的事情,C++ 是強(qiáng)類型語言(”1024” 是字符串類型而不是整數(shù)類型),而 JavaScript 卻總是默認(rèn)的幫我們做一些類型轉(zhuǎn)換。

  JavaScript 的基本類型包括 StringNumber,Boolean,nullundefined,V8 使用類繼承的方式來定義這類型,這些類型都繼承了 Primitive 類,而 Primitive 繼承了 Value v8 也支持整型(包括 Int32 Uint32 ),而所有的類型定義都可以從 V8 類型文檔 中看到,除了基本的類型,還有 Object,Array,Map 等類型的定義。

  基本類型的繼承關(guān)系如下圖:

Node.js 和 C++ 之間的類型轉(zhuǎn)換

V8 中所有 JavaScript 值都是被放在 Local 對象中,通過這個對象指定了 JavaScript 運行時的內(nèi)存單元。

  下面這段代定義了一個 Number 類型的值,其中 Test 函數(shù)中聲明的 isolate 變量代表著 V8 虛擬機(jī)中的堆內(nèi)存,當(dāng)創(chuàng)建新變量的時候就需要用到它,接下來的一行代碼就通過 isolate 聲明了一個 Number 類型的變量。

 #include

#include

 

usingnamespace v8;

 

void Test(const v8::FunctionCallbackInfo & args) {

    Isolate* isolate = args.GetIsolate();

    // 聲明變量

    Local retval = v8::Number::New(isolate, 1000);

}

 

void init(Local exports, Local module) {


    NODE_SET_METHOD(exports, "getTestValue", Test);

}

 

NODE_MODULE(returnValue, init)

  看了 V8 類型 API 文檔 你會發(fā)現(xiàn)對于基本的 JavaScript 類型,只有變量的聲明而沒有變量的賦值。最初想可能覺得這個非常的奇怪,可是仔細(xì)想一想后發(fā)現(xiàn)這個是合理的。主要由以下幾點原因:

  JavaScript 的基本類型是不可變類型,變量都是指向一個不可變的內(nèi)存單元,var a = 10,則 a 指向的內(nèi)存單元中包含的值為 5,重新賦值 a = 100,沒有改變這個內(nèi)存單元的值,而是使得 a 指向了另外一個內(nèi)存單元,其中的值為 100。如果聲明兩個變量 xy 的值都為 10,則他們指向的是同一個內(nèi)存單元。

  函數(shù)的傳參都是傳值,而不是傳引用,當(dāng)在 JavaScript 中調(diào)用 C++ 的函數(shù)時,如果參數(shù)是基本類型則每次都是把這個值拷貝過去,改變參數(shù)的值不會影響原來的值。

  使用 Local 聲明基本類型的變量都是對內(nèi)存單元的引用,因為第一條原因不可能改變引用的值使其指向另外一個內(nèi)存單元,因此不存在變量的重新賦值。

  數(shù)據(jù)流向 C++ -> JavaScript

  下面 demo 定義了一些常用的 JavaScript 類型,包括基本類型的以及 Object, Array, Fuction

  #include

#include

 

usingnamespace v8;

 

void MyFunction(const v8::FunctionCallbackInfo & args) {

    Isolate* isolate = args.GetIsolate();

    args.GetReturnValue().Set(String::NewFromUtf8(isolate, "Hello World!"));

}

 

void Test(const v8::FunctionCallbackInfo & args) {

    Isolate* isolate = args.GetIsolate();

 

    // Number 類型的聲明

    Local retval = v8::Number::New(isolate, 1000);

 

    // String 類型的聲明

    Local str = v8::String::NewFromUtf8(isolate, "Hello World!");

 

    // Object 類型的聲明

    Local obj = v8::Object::New(isolate);


    // 對象的賦值

    obj->Set(v8::String::NewFromUtf8(isolate, "arg1"), str);

    obj->Set(v8::String::NewFromUtf8(isolate, "arg2"), retval);

 

    // Function 類型的聲明并賦值

    Local tpl = v8::FunctionTemplate::New(isolate, MyFunction);

    Local fn = tpl->GetFunction();

    // 函數(shù)名字

    fn->SetName(String::NewFromUtf8(isolate, "theFunction"));

    obj->Set(v8::String::NewFromUtf8(isolate, "arg3"), fn);

 

    // Boolean 類型的聲明

    Local flag = Boolean::New(isolate, true);

    obj->Set(String::NewFromUtf8(isolate, "arg4"), flag);

 

    // Array 類型的聲明

    Local arr = Array::New(isolate);

    // Array 賦值

    arr->Set(0, Number::New(isolate, 1));

    arr->Set(1, Number::New(isolate, 10));

    arr->Set(2, Number::New(isolate, 100));

    arr->Set(3, Number::New(isolate, 1000));

    obj->Set(String::NewFromUtf8(isolate, "arg5"), arr);

 

    // Undefined 類型的聲明

    Local und = Undefined(isolate);

    obj->Set(String::NewFromUtf8(isolate, "arg6"), und);

 

    // null 類型的聲明

    Local null = Null(isolate);

    obj->Set(String::NewFromUtf8(isolate, "arg7"), null);

 

    // 返回給 JavaScript 調(diào)用時的返回值

    args.GetReturnValue().Set(obj);

}

 

void init(Local exports, Local module) {


    NODE_SET_METHOD(exports, "getTestValue", Test);

}

 

NODE_MODULE(returnValue, init)

所有的 addon 都需要一個初始化的函數(shù),如下面的代碼:


void Initialize(Local exports);


NODE_MODULE(module_name, Initialize)

Initialize 是初始化的函數(shù), module_name 是編譯后產(chǎn)生的二進(jìn)制文件名,上述代碼的模塊名為 returnValue 。


上述代碼通過 node-gyp 編譯后(編譯過程官方文檔 C/C++ Addons 有詳細(xì)的介紹),可以通過如下的方式調(diào)用。


// returnValue.node 這個文件就是編譯后產(chǎn)生的文件,通過 NODE_MODULE(returnValue, init) 決定的文件名

const returnValue = require('./build/Release/returnValue.node');

console.log(returnValue.getTestValue());

  運行結(jié)果如下:

Node.js 和 C++ 之間的類型轉(zhuǎn)換

數(shù)據(jù)流向 javaScript -> C++

  上面的 demo 展示了怎樣在在 C++ 定義 JavaScript 類型,數(shù)據(jù)的是從 C++ 流向 JavaScript,反過來數(shù)據(jù)也需要從 javaScript 流向 C++,也就是調(diào)用 C++ 函數(shù)的時候需要傳入一些參數(shù)。

  下面的代碼展示了參數(shù)個數(shù)判斷,參數(shù)類型判斷,以及參數(shù)類型裝換成 V8 類型的過程,包括基本類型以及 Object, Array, Fuction

#include

#include

#include


usingnamespace v8;

usingnamespace std;


void GetArgument(const FunctionCallbackInfo & args) {

    Isolate* isolate = args.GetIsolate();


    // 參數(shù)長度判斷

    if (args.Length() < 2) {

        isolate->ThrowException(Exception::TypeError(

            String::NewFromUtf8(isolate, "Wrong number of arguments")));

        return;

    }


    // 參數(shù)類型判斷

    if (!args[0]->IsNumber() || !args[1]->IsNumber()) {

        //拋出錯誤

        isolate->ThrowException(Exception::TypeError(

            String::NewFromUtf8(isolate, "argumnets must be number")));

    }


    if (!args[0]->IsObject()) {

        printf("I am not Object\n");

    }


    if (!args[0]->IsBoolean()) {

        printf("I am not Boolean\n");

    }


    if (!args[0]->IsArray()) {

        printf("I am not Array\n");

    }


    if (!args[0]->IsString()) {

        printf("I am not String\n");

    }


    if (!args[0]->IsFunction()) {

        printf("I am not Function\n");

    }


    if (!args[0]->IsNull()) {

        printf("I am not Null\n");

    }


    if (!args[0]->IsUndefined()) {

        printf("I am not Undefined\n");

    }


    // js Number 類型轉(zhuǎn)換成 v8 Number 類型

    Local value1 = Local ::Cast(args[0]);

    Local value2 = Local ::Cast(args[1]);

    double value = value1->NumberValue() + value2->NumberValue();


    // js String 類型轉(zhuǎn)換成 v8 String 類型

    Local str = Local ::Cast(args[2]);

    String::Utf8ValueutfValue(str);

    cout<


    // js Array 類型轉(zhuǎn)換成 v8 Array 類型

    Local input_array = Local ::Cast(args[3]);

    printf("%d, %f %f\n", input_array->Length(), input_array->Get(0)->NumberValue(), input_array->Get(1)->NumberValue());


    // js Object 類型轉(zhuǎn)換成 v8 Object 類型

    Local obj = Local ::Cast(args[4]);



    // 根據(jù) key 獲取對象中的值

    Local a = obj->Get(String::NewFromUtf8(isolate, "a"));

    Local b = obj->Get(String::NewFromUtf8(isolate, "b"));


    // js Array 類型轉(zhuǎn)換成 v8 Array 類型

    Local c = Local ::Cast(obj->Get(String::NewFromUtf8(isolate, "c")));

    cout< NumberValue()<<"   "< NumberValue()<

    printf("%d, %f %f\n", c->Length(), c->Get(0)->NumberValue(), c->Get(1)->NumberValue());


    // js String 類型轉(zhuǎn)換成 v8 String 類型

    Local cString = Local ::Cast(c->Get(2));

    String::Utf8ValueutfValueD(cString);

    cout<


    // 根據(jù) key 獲取對象中的值

    Local d = Local ::Cast(obj->Get(String::NewFromUtf8(isolate, "d")));


    Local dString1 = Local ::Cast(d->Get(String::NewFromUtf8(isolate, "m")));

    String::Utf8ValueutfValued1(dString1);

    cout<


    // 根據(jù) key 獲取對象中的值

    Local dString2 = Local ::Cast(d->Get(String::NewFromUtf8(isolate, "n")));

    String::Utf8ValueutfValued2(dString2);

    cout<


    // js Booelan 類型轉(zhuǎn)換成 v8 Boolean 類型

    Local FlagTrue = Local ::Cast(args[5]);

    cout<<"Flag: "< BooleanValue()<


    // js Function 類型轉(zhuǎn)換成 v8 Function 類型

    Local cb = Local ::Cast(args[8]);

    const unsigned argc = 2;

    Local argv[2];

    argv[0] = a;

    argv[1] = b;

    cb->Call(Null(isolate), argc, argv);


    args.GetReturnValue().Set(value);

}


void Init(Local exports, Local module) {


    NODE_SET_METHOD(module, "exports", GetArgument);

}


NODE_MODULE(argumentss, Init)

通過 node-gyp 編譯后,可以通過如下的方式調(diào)用。


const getArguments = require('./build/Release/arguments');


console.log(getArguments(2, 3, 'Hello Arguments', [1, 2, 3], {

        a: 10,

        b: 100,

        c: [23, 22, "我是33"],

        d: { m: '我是22', n: '我是23' }

    }, true, null, undefined,

    function myFunction(...args) {

        console.log('I am Function!');

        console.log(...args);

        console.log('I am Function!');

}));

  運行結(jié)果如下:

Node.js&nbsp;和&nbsp;C++&nbsp;之間的類型轉(zhuǎn)換


關(guān)于其他的類型,我這里就就不一一介紹,V8 文檔里面都有對應(yīng)的 API。

  NAN

  由于 V8 API 還沒有徹底穩(wěn)定下來,所以對于不同版本的 Node.js 類型相關(guān)的 API 會發(fā)生變化,而 NAN 幫我們做了封裝,在編碼的時候不需要關(guān)心版本問題,只需要引入相應(yīng)的頭文件即可。

  引入頭文件后,可以如下使用方式:

  v8::LocalNan::Undefined()v8::LocalNan::Null()


來源:伯樂在線



您還未登錄,請先登錄

熱門帖子

最新帖子

?