国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

使用Node.js Addon實現類繼承

開發 前端
昨天有個同學問怎么通過NAPI把C++類的繼承關系映射到JS,很遺憾,NAPI貌似還不支持,但是V8支持,因為V8在頭文件里導出了這些API,并Node.js里也依賴這些API,所以可以說是比較穩定的。本文介紹一下如何實現這種映射(不確定是否能滿足這位同學的需求)。

[[411576]]

本文轉載自微信公眾號「編程雜技」,作者theanarkh。轉載本文請聯系編程雜技公眾號。

前言:昨天有個同學問怎么通過NAPI把C++類的繼承關系映射到JS,很遺憾,NAPI貌似還不支持,但是V8支持,因為V8在頭文件里導出了這些API,并Node.js里也依賴這些API,所以可以說是比較穩定的。本文介紹一下如何實現這種映射(不確定是否能滿足這位同學的需求)。

下面我們看一下Addon的實現。會涉及到V8的一些使用,可以先閱讀該文章《一段js理解nodejs中js調用c++/c的過程》。首先看一下基類的實現。

  1. #ifndef BASE_H 
  2. #define BASE_H 
  3. #include <stdio.h> 
  4. #include <node.h> 
  5. #include <node_object_wrap.h> 
  6.  
  7. using namespace node; 
  8. using namespace v8; 
  9. class Base: public ObjectWrap { 
  10.     public
  11.         static void New(const FunctionCallbackInfo<Value>& info) { 
  12.             // 新建一個對象,然后包裹到info.This()中,后面會解包出來使用 
  13.             Base* base =  new Base(); 
  14.             base->Wrap(info.This()); 
  15.         } 
  16.  
  17.         static void Print(const FunctionCallbackInfo<Value>& info) { 
  18.             // 解包出來使用 
  19.             Base* base = ObjectWrap::Unwrap<Base>(info.This()); 
  20.             base->print(); 
  21.         } 
  22.  
  23.         void print() { 
  24.             printf("base print\n"); 
  25.         } 
  26.  
  27.         void hello() { 
  28.             printf("base hello\n"); 
  29.         } 
  30. }; 
  31.  
  32. #endif 

Node.js提供的ObjectWrap類實現了Wrap和UnWrap的功能,所以我們可以繼承它簡化封包解包的邏輯。Base類定義了兩個功能函數hello和print,同時定義了兩個類靜態函數New和Print。New函數是核心邏輯,該函數在js層執行new Base的時候會執行并傳入一個對象,這時候我們首先創建一個真正的有用的對象,并且通過Wrap把該對象包裹到傳進來的對象里。我們繼續看一下子類。

  1. #ifndef DERIVED_H 
  2. #define DERIVED_H 
  3. #include <node.h> 
  4. #include <node_object_wrap.h> 
  5. #include"Base.h" 
  6.  
  7. using namespace node; 
  8. using namespace v8; 
  9. class Derived: public Base { 
  10.     public
  11.         static void New(const FunctionCallbackInfo<Value>& info) { 
  12.             Derived* derived =  new Derived(); 
  13.             derived->Wrap(info.This()); 
  14.         } 
  15.  
  16.         static void Hello(const FunctionCallbackInfo<Value>& info) { 
  17.             Derived* derived = ObjectWrap::Unwrap<Derived>(info.This()); 
  18.             // 調用基類的函數 
  19.             derived->hello(); 
  20.         } 
  21. }; 
  22.  
  23. #endif 

子類的邏輯類似,New函數和基類的邏輯一樣,除了繼承基類的方法外,額外定義了一個Hello函數,但是我們看到這只是個殼子,底層還是調用了基類的函數。定義完基類和子類后,我們把這兩個類導出到JS。

  1. #include <node.h> 
  2. #include "Base.h" 
  3. #include "Derived.h" 
  4.  
  5. namespace demo { 
  6.  
  7. using v8::FunctionCallbackInfo; 
  8. using v8::Isolate; 
  9. using v8::Local
  10. using v8::Object; 
  11. using v8::String; 
  12. using v8::Value; 
  13. using v8::FunctionTemplate; 
  14. using v8::Function
  15. using v8::Number; 
  16. using v8::MaybeLocal; 
  17. using v8::Context; 
  18. using v8::Int32; 
  19. using v8::NewStringType; 
  20.  
  21. void Initialize( 
  22.   Local<Object> exports, 
  23.   Local<Value> module, 
  24.   Local<Context> context 
  25. ) { 
  26.   Isolate * isolate = context->GetIsolate(); 
  27.   // 新建兩個函數模板,基類和子類,js層New導出的函數時,V8會執行New函數并傳入一個對象 
  28.   Local<FunctionTemplate> base = FunctionTemplate::New(isolate, Base::New); 
  29.   Local<FunctionTemplate> derived = FunctionTemplate::New(isolate, Derived::New); 
  30.  
  31.   // js層使用的類名 
  32.   NewStringType type = NewStringType::kNormal; 
  33.   Local<String> base_string = String::NewFromUtf8(isolate, "Base", type).ToLocalChecked(); 
  34.   Local<String> derived_string = String::NewFromUtf8(isolate, "Derived", type).ToLocalChecked(); 
  35.  
  36.   // 預留一個指針空間 
  37.   base->InstanceTemplate()->SetInternalFieldCount(1); 
  38.   derived->InstanceTemplate()->SetInternalFieldCount(1); 
  39.  
  40.   // 定義兩個函數模板,用于屬性的值 
  41.   Local<FunctionTemplate> BasePrint = FunctionTemplate::New(isolate, Base::Print); 
  42.   Local<FunctionTemplate> Hello = FunctionTemplate::New(isolate, Derived::Hello); 
  43.  
  44.   // 給基類定義一個print函數 
  45.   base->PrototypeTemplate()->Set(isolate, "print", BasePrint); 
  46.   // 給子類定義一個hello函數 
  47.   derived->PrototypeTemplate()->Set(isolate, "hello", Hello); 
  48.   // 建立繼承關系 
  49.   derived->Inherit(base); 
  50.   // 導出兩個函數給js層 
  51.   exports->Set(context, base_string, base->GetFunction(context).ToLocalChecked()).Check(); 
  52.   exports->Set(context, derived_string, derived->GetFunction(context).ToLocalChecked()).Check(); 
  53.  
  54. NODE_MODULE_CONTEXT_AWARE(NODE_GYP_MODULE_NAME, Initialize) 

我們看到給基類原型定義了一個print函數,給子類定義了hello函數。最后我們看看如何在JS層使用。

  1. const { Base, Derived } = require('./build/Release/test.node'); 
  2. const base = new Base(); 
  3. const derived = new Derived(); 
  4. base.print(); 
  5. derived.hello(); 
  6. derived.print(); 
  7. console.log(derived instanceof Base, derived instanceof Derived) 

下面是具體的輸出

  1. base print 
  2. base hello 
  3. base print 
  4. true true 

我們逐句分析

1 base.print()比較簡單,就是調用基類定義的Print函數。

2 derived.hello()看起來是調用了子類的Hello函數,但是Hello函數里調用了基類的hello函數,實現了邏輯的復用。

3 derived.print()子類沒有實現print函數,這里調用的是基類的print函數,和1一樣。

4 derived instanceof Base, derived instanceof Derived。根據我們的定義,derived不僅是Derived的實例,也是Base的實例。

實現代碼分析完了,我們看到把C++類映射到JS的方式有兩種,第一種就是兩個C++ 類沒有繼承關系,通過V8的繼承API實現兩個JS層存在繼承關系的類(函數),比如print函數的實現,我們看到子類沒有實現print,但是可以調用print,因為基類定義了,Node.js就是這樣處理的。第二種就是兩個存在繼承關系的C++類,同樣先通過V8的API實現兩個繼承的類導出到JS使用,因為JS層使用的只是殼子,具體執行到C++代碼的時候,我們再體現出這種繼承關系。比如Hello函數的實現,雖然我們是在子類里導出了hello函數,并且JS執行hello的時候的確執行到了子類的C++代碼,但是最后會調用基類的hello函數。

最后我們通過Nodej.js看看是如何做這種映射的,我們通過PipeWrap.cc的實現進行分析。

  1. // 新建一個函數模板 
  2. Local<FunctionTemplate> t = env->NewFunctionTemplate(New);// 繼承兩個函數模板 
  3. t->Inherit(LibuvStreamWrap::GetConstructorTemplate(env));// 導出給JS使用 
  4. exports->Set(env->context(), 
  5.               pipeString, 
  6.               t->GetFunction(env->context()).ToLocalChecked()).Check(); 

上面代碼實現了繼承,我們看看GetConstructorTemplate的實現。

  1. tmpl = env->NewFunctionTemplate(nullptr); 
  2. env->SetProtoMethod(tmpl, "setBlocking", SetBlocking); 
  3. env->SetProtoMethod(tmpl, "readStart", JSMethod<&StreamBase::ReadStartJS>); 
  4. env->SetProtoMethod(t, "readStop", JSMethod<&StreamBase::ReadStopJS>);// ... 

上面代碼新建了一個新的函數模板并且設置了一系列的原型屬性,那么模板t就繼承了這些屬性。我們看看Node.js里怎么使用的。

  1. function createHandle(fd, is_server) { 
  2.   // ... 
  3.   return new Pipe( 
  4.       is_server ? PipeConstants.SERVER : PipeConstants.SOCKET 
  5.   );} 
  6.  
  7. this._handle = createHandle(fd, false); 
  8. err = this._handle.setBlocking(true); 

上面的代碼首先會創建一個Pipe對象,然后調用它的setBlocking方法。我們發現Pipe(pipe_wrap.cc)是沒有實現setBlocking函數的,但是好為什么他可以調用setBlocking呢?答案就是它的基類實現了。

后記:在JS里實現繼承是簡單的,但是在底層實現起來還是比較復雜的,但是從代碼設計的角度來看是非常有必要的。

代碼可以在倉庫獲取:

https://github.com/theanarkh/learn-to-write-nodejs-addons。

 

 

責任編輯:武曉燕 來源: 編程雜技
相關推薦

2023-11-24 14:54:03

Node.jsElectronAddon

2014-04-10 09:43:00

Node.jsTwilio

2022-08-28 16:30:34

Node.jsDocker指令

2020-08-07 10:40:56

Node.jsexpress前端

2023-01-10 14:11:26

2013-11-01 09:34:56

Node.js技術

2015-03-10 10:59:18

Node.js開發指南基礎介紹

2021-03-09 08:03:21

Node.js 線程JavaScript

2021-03-03 06:39:05

Nodejs前端開發

2021-07-30 11:20:53

JavaScriptNode.jsWeb Develop

2016-08-25 21:28:04

前端node截圖

2022-08-22 07:26:32

Node.js微服務架構

2012-09-29 11:13:15

Node.JS前端開發Node.js打包

2011-11-01 10:30:36

Node.js

2011-09-02 14:47:48

Node

2011-09-09 14:23:13

Node.js

2011-09-08 13:46:14

node.js

2012-10-24 14:56:30

IBMdw

2011-11-10 08:55:00

Node.js

2021-03-01 08:03:26

Node.jsStream模塊
點贊
收藏

51CTO技術棧公眾號

亚洲国产成人91精品| 中文字幕校园春色| 日本视频一区二区不卡| 在线中文字幕视频| 国产日韩欧美三区| 欧美日本不卡高清| 欧美绝品在线观看成人午夜影视| 香蕉网站在线| 亚洲精品日日夜夜| 国产欧美一区二区三区在线看| 男人av在线播放| 国产传媒一区在线| 日韩二区三区在线| 国产精品日韩三级| 加勒比久久综合| 亚洲成人激情视频| 精品日韩在线播放| 亚洲国内欧美| 国产精品成人免费视频| 国产美女高潮在线观看| 日韩一区二区中文字幕| 偷拍25位美女撒尿视频在线观看| 中文字幕不卡三区| 亚洲精品中文综合第一页| 风间由美性色一区二区三区四区| 国产亚洲精品一区二555| ga∨成人网| 精品亚洲aⅴ乱码一区二区三区| 国产免费高清一区| 欧美福利影院| 国产精品日本精品| 毛片毛片毛片毛片| 99久久精品免费| 日本成人看片网址| 红杏一区二区三区| 亚洲国产精品久久91精品| 国产91久久久久蜜臀青青天草二| 亚洲第一视频网| 成人国产激情| 久久精品99无色码中文字幕| 9i精品一二三区| 久久久国产精品午夜一区ai换脸| www.av在线| 欧美午夜激情在线| 丝袜在线视频| 日韩av网站大全| 成人国产精品色哟哟| 熟妇人妻va精品中文字幕| 午夜视频在线| 欧美影视一区| 精品日本高清在线播放| 不卡av电影院| 怡红院av亚洲一区二区三区h| 成人午夜影视| 亚洲成aⅴ人片久久青草影院| 极品销魂美女一区二区三区| 欧美日韩视频专区在线播放| 欧美在线一区二区三区四区| 久久米奇亚洲| 日韩精品久久久久久久电影99爱| 不卡视频一二三四| 亚洲少妇激情视频| 久久久久免费看黄a片app| 麻豆福利在线观看| 亚洲一区日韩在线| 欧美一区日本一区韩国一区| 国产精品自产拍在线观| 一级黄色av| 91精品二区| 亚洲综合色自拍一区| 欧美激情视频网址| 黄污在线观看| 一二三区精品| 欧美高清视频在线高清观看mv色露露十八 | av高清不卡在线| 一本色道久久88精品综合| 91免费黄视频| 国产一区一区| 一区二区三区欧美在线观看| 91原创国产| heyzo一区| 国产精品一区二区久久精品爱涩| 在线观看一区不卡| 日韩欧美一级在线| 亚洲天堂2016| 91看片就是不一样| 欧美午夜精品理论片a级按摩| 国产精品久久久久久吹潮| 91老司机在线| 国产精品乱人伦中文| 伊人成综合网站| 欧日韩一区二区三区| 亚洲一级二级三级| 国产精品99| 天堂av在线中文| 日韩精品一区在线观看| 亚洲成人免费| 国产剧情av在线| 4k岛国日韩精品**专区| 精品久久久久久亚洲国产300| 亚洲图区一区| 亚洲一区二区偷拍精品| 国产黄色片在线观看| 日本一区二区免费在线| 精品久久久久久久久久中文字幕| 日韩一区三区| 欧美tk丨vk视频| 日韩精品福利| 国产喂奶挤奶一区二区三区| 91视频国产一区| 日本午夜精品久久久| 一区二区三区四区视频| 91www在线| 国产一区二区三区丝袜| 色女人在线视频| 欧美日韩电影一区| 天天av综合网| 亚洲第一主播视频| 黄色动漫网站入口| 精品中文字幕一区二区| 日韩美女视频在线观看| 日韩国产激情| 九九综合九九综合| 日韩免费在线电影| 日韩美女毛茸茸| 在线日韩中文| 欧美大香线蕉线伊人久久| 国产人伦精品一区二区| 成人福利视频在| 日韩中文字幕在线免费观看| 亚洲电影男人天堂| 国产精品揄拍一区二区| 精品一二三四在线| 成人av福利| 8050国产精品久久久久久| 另类小说视频一区二区| 九色porny自拍| 欧美日韩一区二区电影| 在线观看福利电影| 午夜精品视频在线| 成人精品亚洲| 久久夜色撩人精品| 国产一区二区三区四区老人| 国产精品久久久久7777婷婷| 久久婷婷蜜乳一本欲蜜臀| 国产成人精品一区二区三区福利| 亚洲日本国产| 亚洲第一区视频| 国产精品手机在线| 精品蜜桃在线看| 亚洲综合激情| 日韩影片中文字幕| 欧美一区二区三区四区五区六区| 18欧美亚洲精品| 极品少妇一区二区三区| 在线观看涩涩| 久久久久免费精品| 国产精品久久久久久网站| 一区二区不卡在线播放| 欧美日韩国产高清| 国产美女久久| 亚洲 欧美 日韩 国产综合 在线 | 亚洲精品中文在线观看| 成人在线视频你懂的| 加勒比海盗1在线观看免费国语版| 欧美性精品220| 999久久久91| 国产专区在线播放| 日本在线视频www| 久久这里只有精品99| 激情欧美日韩一区二区| 日韩高清不卡在线| 国产精品午夜春色av| 美女视频一区二区三区| 国产精品亚洲二区在线观看| 九七影院97影院理论片免费| 最近日韩中文字幕中文| 日本不卡视频一二三区| 香蕉视频在线看| 91久久久久久久久久| 欧美日韩在线观看视频| 欧美日韩国产免费观看视频| 一级毛片在线| 5566中文字幕一区二区| 777色狠狠一区二区三区| 美女久久一区| 欧美影视资讯| 你懂的av在线| 国产成人一区二区三区电影| 午夜精品123| 老鸭窝91久久精品色噜噜导演| 麻豆视频免费在线观看| 综合网五月天| 欧美成人一二三| 亚洲国产日韩a在线播放性色| 亚洲一级网站| 你懂的免费在线观看| 亚洲伊人第一页| 久久精品二区| 在线播放中文一区|