溫故而知新,可以為濕矣
首先請大家記住這個 V8 的線上手冊——http://izs.me/v8-docs/main.html。
還記得上次的 building.gyp 檔案嗎?
就像這樣,舉一反三,如果多幾個 *.cc 檔案的話就是這樣的:
"sources": [ "addon.cc", "myexample.cc" ]
上次我們把倆步驟分開了,實際上配置和編譯可以放在一起的:
$ node-gyp configure build
複習完了嗎?沒? !
好的,那我們繼續吧。
表番
函數參數
現在我們終於要講參數了呢。
讓我們設想有這樣一個函數 add(a, b) 代表把 a 和 b 相加回傳結果,所以先把函數外框寫好:
Handle
{
HandleScope scope;
//... 又來!
}
Arguments
這個就是函數的參數了。我們不妨先看看 v8 的官方手冊參考。
•int Length() const
•Local
其它的我們咱不關心,這兩個可重要了!一個代表傳入函數的參數個數,另一個中括號就是透過下標索引來存取第 n 個參數的。
所以如上的需求,我們大致就可以理解為 args.Length() 為 2,args[0] 代表 a 以及 args[1] 代表 b 了。而我們要判斷這兩個數的型別必須得是 Number。
注意到沒,中括號的索引運算子回傳結果是一個 Local
•IsArray()
•IsBoolean()
•IsDate()
•IsFunction()
•IsInt32()
•IsNativeError()
•IsNull()
•IsNumber()
•IsRegExp()
•IsString()
•...
我就不一一列舉了,剩下的自己看文件。 。:.゚ヽ(*´∀`)ノ゚.:。
ThrowException
這個是我們等下要用到的一個函數。具體在 v8 文檔中可以找到。
顧名思義,就是拋出錯誤啦。執行這個語句之後,相當於在 Node.js 本地檔中執行了一條 throw() 語句一樣。比如說:
ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
就相當於執行了一條 Node.js 的:
throw new TypeError("Wrong number of arguments");
Undefined()
這個函數呢也在文檔裡面。
具體就是一個空值,因為有些函數並不需要傳回什麼特定的值,或是說沒有回傳值,這個時候就需要用 Undefined() 來取代了。
動手吧騷年!
在理解了以上的幾個要點之後,我相信你們很快就能寫出 a b 的邏輯了,我就把 Node.js 官方手冊的程式碼抄過來給你們過一遍就算完事了:
Handle
{
HandleScope scope;
// 代表了可以傳入 2 個以上的參數,但實際上我們只用前兩個
if(args.Length()
{
// 拋出錯誤
ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
// 回傳空值
return scope.Close(Undefined());
}
// 若前兩個參數其中一個不是數字的話
if(!args[0]->IsNumber() || !args[1]->IsNumber())
{
// 拋出錯誤並回傳空值
ThrowException(Exception::TypeError(String::New("Wrong arguments")));
return scope.Close(Undefined());
}
// 具體參考 v8 文件
// http://izs.me/v8-docs/classv8_1_1Value.html#a6eac2b07ed58f1761bbfd53bf0e366dced58f1761bbfd53bf0e366
dc
// 的 `NumberValue` 函數
return scope.Close(num);
}
函數大功告成!
最後把尾部的導出函數給寫好就 OK 了。
程式碼如下:
你會看到一個 2b ! ✧。٩(ˊᗜˋ)و✧*。
回呼函數
上一章我們只講了個 Hello world,這一章阿婆主就良心發現一下,再來個回調函數的寫法。
慣例我們先寫好框架:
Handle
{
// ... 噼裡啪啦噼裡啪啦
return scope.Close(Undefined());
接著我們決定它的用法是這樣的:
func(function(msg) {
console.log(msg);
});
即它會給回呼函數傳入一個參數,我們設想它是一個字串,然後我們可以 console.log() 出來看。
首先你要有一個字串系列
廢話不多說,先給它一個字串餵飽了再說吧。 (√ ζ ε:)
不過我們得讓這個字串是通用型別的,因為 Node.js 程式碼是弱型別的。
Local
什麼?你問我什麼是 Local
那我稍稍講一下吧,參考自這裡和V8參考文件。
如文檔所示,Local
然後下面就是講 Local 了。
Handle 有兩種類型, Local Handle 和 Persistent Handle ,類型分別是 Local
然後你要有個參數表系列
終端命令列呼叫 C/C 之後怎麼取命令列參數?
void main(int argc, char* argv[])
{
// ...
}
對了,這裡的 argc 就是命令列參數個數,argv[] 就是各個參數了。那麼呼叫 Node.js 的回呼函數,v8 也採用了類似的方法:
~~QAQ 卡在了 Handle
經過我多方面求證(SegmentFault和StackOverflow以及一個扣扣群),終於解決了上面這個函數仨參數的意思。
後面兩個參數就不多說了,一個是參數個數,另一個就是一個參數的數組了。至於第一個參數 Handle
It is the same as apply in JS. In JS, you do
最初の引数として渡されるオブジェクトは、関数スコープ内で this になります。JS について詳しくない場合は、ここで JS の詳細を参照してください。http://unschooled.org /2012/03/undering-javascript-this/
——StackOverflow
つまり、その機能は呼び出される関数の this ポインタを指定することです。この Call の使用法は、JavaScript の binding()、call()、および apply() に似ています。
したがって、私たちがしなければならないことは、最初にパラメータテーブルを構築し、次に実行のために Call 関数を渡すことです。
最初のステップは変換関数を表示することです。変換関数は元々オブジェクト型であるためです。
ローカル cb = ローカル::Cast(args[0]);
2 番目のステップは、パラメーター テーブル (配列) を作成することです:
Local
ラストコール機能シリーズ
cb を呼び出してパラメータを渡します:
cb->Call(Context::GetCurrent()->Global(), 1, argv);
ここでの最初のパラメータ Context::GetCurrent()->Global() は、関数の this としてグローバル コンテキストを取得することを意味します。2 番目のパラメータはパラメータ テーブル内の番号です (結局、Node.js ですが)。配列には長さ属性がありますが、実際にはシステムは C の配列の長さを知らないため、配列の長さを示すために自分で数値を渡す必要があります); 最後のパラメーターは作成したばかりのパラメーター テーブルです。 。
最終章ファイナルドキュメントシリーズ
関数を作成し、それをエクスポートされた関数に入れて、最後に宣言するというこのステップについては、誰もがすでによく知っていると思います。
コードを直接リリースするだけですが、Node.js ドキュメントに直接アクセスすることもできます。
ハンドル<値>RunCallback(const Arguments& args)
{
HandleScope スコープ;
ローカル cb = ローカル::Cast(args[0]);
const unsigned argc = 1;
Local
cb->Call(Context::GetCurrent()->Global(), argc, argv);
returnscope.Close(Unknown());
}
void Init(Handle
NODE_MODULE(アドオン、初期化)
完了しました。残りの手順は自分で実行してください。この関数を JS で呼び出すことについては、以前に説明しました。
追加
さて、勉強ノートがどんどん自由になってきている気がしますので、分解してください~
今日はこの辺で、勉強ノートを書いている途中でCall関数のパラメータの意味などでまた困ってしまいました。
この一連の学習ノートがまだ役立つと思われる場合は、ぜひ一緒に楽しんでください〜Σ>―(〃°ω°〃)♡→