JS在线运行

版本:

所属目录
点击了解高性能代码运行API
运行结果
教程手册
代码仓库
极速运行
终端运行
图形+终端

                        
以下是用户最新保存的代码
最小矩阵宽度(从第一列开始一列列加,直到判断子矩阵内包含数组的所有元素) 发布于:2025-04-16 19:10 最小交付时间(二分+回溯:先将数组排序,最小值start=Math.max(arr),最大值end = arr.reduce,回溯中创建一个新的工人数组,每次遍历数组时将数组中的每一个元素都尝试分配给worker[i]) 发布于:2025-04-16 18:53 阿里巴巴找黄金宝箱Ⅳ(单调栈:栈中存储单调递减的元素的集合,当找到比栈顶元素大的元素时,循环出栈直到栈顶元素不小于当前元素) 发布于:2025-04-15 17:47 找出经过特定点的路径长度(dfs+回溯) 发布于:2025-04-14 16:32 计算最接近的数(1.输入处理;2.对数组进行深拷贝,然后对新数组进行排序,之后在进行后续操作) 发布于:2025-04-14 15:11 MELON的难题(01背包问题:先判断数组和是否为偶数,如果为偶数直接输出-1,target=sum/2 状态转移方程dp[i]=Math.min(dp[i],dp[i-1]+1) 发布于:2025-04-11 17:29 简易内存池(模拟,双指针) 发布于:2025-04-11 17:12 通过软盘拷贝文件 这是一个典型的 0-1 背包问题的变体: 问题描述: 有一个容量为 1.44MB(1474560字节)的软盘 每个块大小为 512 字节 需要在有限容量内存储最大的文件字节总和 关键点: 文件大小以字节为单位 存储空间以块为单位 即使文件不足一个块,也要占用整个块的空间 动态规划解析: 状态定义:dp[i] 表示使用 i 个块时能存储的最大字节数 状态转移:对每个文件,可以选择放入或不放入 约束条件:总块数不能超过软盘容量 时间复杂度:O(n maxSize),其中: n 是文件数量 maxSize 是软盘最大块数(约2880块) 发布于:2025-04-11 16:39 正整数到excel编号之间的转换(对num先进行取余操作,取余之后的值就是字母a往后的偏移量,letter=String.fromCharCode('a'.charCodeAt(0)+remain),将这个字母放到结果队首,然后对num进行整除,循环直到num为0) 发布于:2025-04-10 17:46 最少交换次数(滑动窗口:先算出整个数组内<k的个数,作为窗口大小,然后再算出0-window内>=k的个数,作为res的初始值,然后滑动窗口,当arr[left]>=k时,res--,当arr[right]>=k时,res++) 发布于:2025-04-10 17:40 TLV解析 Ⅱ(字符串操作) 发布于:2025-04-10 16:24 最少有多少个小朋友了(相同的数字的个数/(相同个数+1)*(相同个数+1)) 发布于:2025-04-10 15:11 硬件产品销售方案(回溯 backtrack(path,val,sum)=>) 发布于:2025-04-09 18:40 猴子爬山(动态规划:状态转义方程dp[i]=dp[i-1]+dp[i-3]) 发布于:2025-04-09 18:14 检测工具代码 发布于:2025-04-09 18:03 检查是否存在满足条件的数字组合)(双指针,然后多重判断) 发布于:2025-04-09 17:45 阿里巴巴找黄金宝箱III(遍历数组,用map储存arr[i]上一次出现的下标,如果当前下标位置i-map.get(i)<=k,直接输出left) 发布于:2025-04-09 17:07 阿里巴巴找黄金宝箱II(数组排序,每次都找最大的减) 发布于:2025-04-09 16:48 全量和已占用字符集(字符串操作) 发布于:2025-04-09 16:34 微服务的集成测试(dfs:当扫描到第i行的第i个元素为1时,就递归dfs,sum+=Math.max(max,dfs(j))) 发布于:2025-04-09 16:25 经典屏保问题(判断是否反向:右下角坐标值为(x+50,y+25),当右下角撞到下面或者右边的墙时,就将x轴/y轴的移动方向反向,左上角同理。) 发布于:2025-04-08 18:37 阿里巴巴找黄金宝箱(I)(左右数组的和,如果左右数组的和相等,就输出) 发布于:2025-04-08 16:57 告警抑制(Map) 发布于:2025-04-08 16:35 过滤组合字符串(全排列:回溯) 发布于:2025-04-03 18:56 分糖果(判断是否为偶数,如果为偶数,操作次数+1,n=n/2;如果为奇数,判断(n+1)/2是否为偶数,如果是偶数,n=n+1,res++,否则n=n-1,res++) 发布于:2025-04-03 18:24 查找接口成功率最优时间段(用前缀和求出[left,right]区间的和,然后求平均值,和输入值比较,如果<=平均值,就移动右指针,如果>平均值,说明当前位置有一个当前最大的区间,比较这个区间是否为最大,如果不是则继续,如果是最大,则更新res结果;如果和当前的i最大值一样,那就将两个都放入到res中。最后,如果left和right不相等,说明最后一个窗口没处理完成,需要单独处理) 发布于:2025-04-03 18:15 游戏分组(dfs // 深度优先搜索函数 // 参数说明: // idx: 当前考虑的数组索引 // level: 当前已选择的数字个数 // subSum: 当前已选择数字的和 // totalSum: 整个数组的总和) 发布于:2025-04-03 17:18 新学校选址(找到一个数组排序后的中位数,如果是基数就是这个数,如果是偶数就是这个数的前一个数) 发布于:2025-04-03 16:38 绘图机器(从(0,0)到第一个点时,是先走横坐标,再走纵坐标,所以第一个点的面积应该为0) 发布于:2025-04-02 19:14 素数之积(判断是否为素数的函数:function isPrime(n) { if (n < 2) return false; for (let i = 2; i <= Math.sqrt(n); i++) { if (n % i === 0) return false; } return true; } 发布于:2025-04-02 17:43 考勤信息(滑动窗口统计七天之内的考勤状况) 发布于:2025-04-02 17:27 打印机队列(简单的数组模拟) 发布于:2025-04-02 16:29 JS AES128加解密 发布于:2025-04-03 15:28 找出重复代码】(二维动态规划:定义二维数组dp,初始值设为0,循环两个字符串,如果str1[i]=str2[j],dp[i+1][j+1]==dp[i][j]+1;使用maxLength定义当前最大的公共子串长度,如果dp[i+1][j+1]>maxLength,记录maxLength和当前结束位置i+1。循环后,根据maxLength和结束位置p,确定silce的范围 发布于:2025-04-01 19:24 【二叉树中序遍历】(用栈将二叉树的结构处理出来。然后中序遍历) 发布于:2025-04-01 19:08 【最小调整顺序次数】(模拟队列操作:当插入操作为头操作时,如果数组不为空,就不是排序状态。尾插入不影响;当移除元素时,如果当前队列是有序的 ,就不需要操作,否则就需要操作,ans++) 发布于:2025-04-01 18:29 二元组个数】(用map存储第一个数组中出现的元素及个数,然后遍历第二个数组,如果遇到map中的元素,ans+=map.get()) 发布于:2025-04-01 18:02 【文件目录大小】(递归:先读取每个文件的信息,解析每行输入的三个部分:id,size,child并将处理过后的放入files中,files:{id,size,child}。然后递归计算目标目录的大小:自定义一个递归函数 getSize,将目标目录设为root节点,向下递归子文件夹,如果有子文件夹就递归计算所有子节点的大小并累加,最后返回结果) 发布于:2025-04-01 17:49 华为OD机试真题 Python 实现【水库蓄水问题】(变体接雨水问题,用双指针遍历数组,然后将子数组内的每一个数字能接到的雨水相加(如果当前位置数字 小于左右边界的最小值,能够接水),如果有多个位置接的雨水相同,保留right-left最小的) 发布于:2025-04-01 17:23 找出两个整数数组中同时出现的整数】(用map存储第一个数组中的元素,然后再循环第二个数组,当遇到map中有的数字时,记录下这个数字。再创建新的Map,按出现次数分组存储数字// 获取当前数字及其在第一个数组中的出现次数// 将数字添加到对应次数的组中,并保持组内数字有序;// 获取所有出现次数并按升序排序// 按格式输出结果) 发布于:2025-04-01 16:47 模拟消息队列(两个数组,一个用来存消息,一个用来存接受者,接受者的中包括订阅时间取消时间和能接收到的消息,正序循环message数组,在逆序循环接受者数组,每当有发送消息的时间在订阅和取关之间时,把这个消息放到消息队列中) 发布于:2025-04-01 16:22 【投篮大赛】(简单字符串操作) 发布于:2025-04-01 16:05 【数值同化】(广度优先搜索,搜索能够到达的所有格子,然后遍历矩阵找出无法到达的地区) 发布于:2025-04-01 15:29 数字加减游戏(数学问题:先判断目标-初始是否能被b整除,如果能直接输出0.如果不能就每次判断初始值+a*x或初始值-a*x是否能整除b,如果能,就时最优解) 发布于:2025-04-01 15:10 数组二叉树(// 遍历树中的所有节点,寻找最小的叶子节点 // 判断当前节点是否为叶子节点,需满足以下条件: // 1. 节点值不为 -1(不是空节点) // 2. 节点值小于当前找到的最小叶子值 // 3. 左子节点不存在(超出数组范围或为-1) // 4. 右子节点不存在(超出数组范围或为-1) // 更新最小叶子节点的索引和值,找到叶子节点后,根据叶子节点不断向上推导出父节点,直到找到根节点。对于索引i,其父节点索引为 floor((i-1)/2)) 发布于:2025-04-01 14:56 【招聘】计算至少需要的面试官数量( // 核心算法思路: // 1. 首先对所有面试时间区间按开始时间排序 // 2. 检查相邻区间是否存在时间重叠 // 3. 对于重叠的区间,需要额外的面试官 // 4. 最后根据重叠情况和每个面试官的面试次数限制(m)计算所需面试官总数) 发布于:2025-03-31 18:44 查找一个有向网络的头节点和尾节点(读取输入数据并解析 统计每个节点的入度和出度 使用Map存储节点的入度和出度 每处理一条边,同时更新起点和终点的度数 入度为0的节点是起点 出度为0的节点是终点 终点需要降序排序 检查是否存在起点和终点 收集所有起点和终点 对终点进行排序 输出结果) 发布于:2025-03-31 17:51 数字序列比大小(田忌赛马:首先对两个数组进行升序排序 对arrA中的每个元素: 在arrB中查找第一个大于等于它的元素 如果找到,使用该位置的前一个元素进行匹配(得1分) 如果找不到,使用arrB的最后一个元素(得-1分)) 发布于:2025-03-31 17:20 寻找最大价值的矿堆(BFS函数实现: 参数:起始位置(i,j) 功能: 计算从起始位置开始的连通区域的和 使用BFS遍历所有相邻的位置 将已访问的位置标记为0 返回连通区域的和 主要流程: 读取矩阵数据 遍历矩阵的每个位置 对未访问的位置进行BFS 更新最大连通区域的和 关键点: 使用0标记已访问的位置 只处理值大于0的位置 考虑四个方向的相邻位置 使用Math.max更新最大和) 发布于:2025-03-31 16:53 仿LISP运算(遍历输入字符串的每个字符,遇到右括号或空格时,处理已收集的字符 遇到右括号时,进行运算,收集非括号和空格的字符;运算时从栈中弹出两个操作数和一个运算符,根据运算符执行相应的运算,将运算结果压入栈中,处理除数为0的特殊情况) 发布于:2025-03-31 16:35 [更多]
显示目录

C/C++ 插件



学习嵌入式的绝佳套件,esp8266开源小电视成品,比自己去买开发板+屏幕还要便宜,省去了焊接不当搞坏的风险。 蜂鸣版+触控升级仅36元,更强的硬件、价格全网最低。

点击购买 固件广场

C/C++ 插件

Node.js Addons(插件)是动态链接的共享对象。他提供了C/C++类库能力。这些API比较复杂,他包以下几个类库:

  • V8 JavaScript, C++类库。用来和JavaScript交互,比如创建对象,调用函数等等。

  • libuv,C事件循环库。等待文件描述符变为可读,等待定时器,等待信号时,会和libuv打交道。或者说,如果你需要和I/O打交道,就会用到libuv。

  • 内部Node类库。其中最重要的类node::ObjectWrap,你会经常派生自它。

Node已经将所有的依赖编译成可以执行文件,所以你不必当心这些类库的链接问题。

Hello world

现在我们来写一个C++插件的小例子,它的效果和以下JS代码一致:

module.exports.hello = function() { return 'world'; };

通过以下代码来创建hello.cc文件:

// hello.cc
#include  <node.h>

using namespace v8;

void  Method(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);
  args.GetReturnValue().Set(String::NewFromUtf8(isolate, "world"));
}

void  init(Handle<Object> exports) {
  NODE_SET_METHOD(exports, "hello", Method);
}

NODE_MODULE(addon, init)

注意:所有的Node插件必须输出一个初始化函数:

void Initialize (Handle<Object> exports);
NODE_MODULE(module_name, Initialize)

NODE_MODULE 之后的代码没有分号,因为它不是一个函数 (参见 node.h )。

module_name 必须和二进制文件名字一致 (后缀是.node)。

源文件会编译成 addon.node 二进制插件。为此我们创建了一个很像JSON的 binding.gyp 文件,它包含配置信息,这个文件用node-gyp编译。

{
  "targets": [
    {
      "target_name": "addon",
      "sources": [ "hello.cc" ]
    }
  ]
}

下一步创建一个 node-gyp configure 工程,在平台上生成这些文件。

创建后,在 build/ 文件夹里拥有一个 Makefile (Unix系统) 文件或者 vcxproj 文件(Windows 系统)。接着调用 node-gyp build 命令编译,生成 .node 文件。这些文件位于 build/Release/ 目录里。

现在,你能在Node工程中使用这些二进制扩展插件,在 hello.js 中声明 require 之前编译的 hello.node :

// hello.js
var addon = require('./build/Release/addon');

console.log(addon.hello()); // 'world'

插件模式

下面是一些addon插件的模式,帮助你开始编码。v8 reference文档里包含v8的各种接口,Embedder's Guide这个文档包含各种说明,比如handles, scopes, function templates等等。

在使用这些例子前,你需要先用node-gyp编译。创建binding.gyp 文件:

{
  "targets": [
    {
      "target_name": "addon",
      "sources": [ "addon.cc" ]
    }
  ]
}

将文件名加入到sources数组里就可以使用多个.cc文件,例如 :

"sources": ["addon.cc", "myexample.cc"]

准备好binding.gyp文件后, 你就能配置并编译插件:

$ node-gyp configure build

函数参数

从以下模式中解释了如何从JavaScript函数中读取参数,并返回结果。仅需要一个addon.cc文件:

// addon.cc
#include <node.h>

using namespace v8;

void Add(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  if (args.Length() < 2) {
    isolate->ThrowException(Exception::TypeError(
        String::NewFromUtf8(isolate, "Wrong number of arguments")));
    return;
  }

  if (!args[0]->IsNumber() || !args[1]->IsNumber()) {
    isolate->ThrowException(Exception::TypeError(
        String::NewFromUtf8(isolate, "Wrong arguments")));
    return;
  }

  double value = args[0]->NumberValue() + args[1]->NumberValue();
  Local<Number> num = Number::New(isolate, value);

  args.GetReturnValue().Set(num);
}

void Init(Handle<Object> exports) {
  NODE_SET_METHOD(exports, "add", Add);
}

NODE_MODULE(addon, Init)

可以用以下的JavaScript代码片段测试:

// test.js
var addon = require('./build/Release/addon');

console.log( 'This should be eight:', addon.add(3,5) );

回调Callbacks

你也能传JavaScript函数给C++函数,并执行它。在addon.cc中:

// addon.cc
#include  <node.h>

using namespace v8;

void  RunCallback(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  Local<Function> cb = Local<Function>::Cast(args[0]);
  const unsigned argc = 1;
  Local<Value> argv[argc] = { String::NewFromUtf8(isolate, "hello world") };
  cb->Call(isolate->GetCurrentContext()->Global(), argc, argv);
}

void  Init(Handle<Object> exports, Handle<Object> module) {
  NODE_SET_METHOD(module, "exports", RunCallback);
}

NODE_MODULE(addon, Init)

注意,这个例子中使用了Init()里的2个参数,module对象是第二个参数。它允许addon使用一个函数完全重写exports。

可以用以下的代码来测试:

// test.js
var addon = require('./build/Release/addon');

addon(function(msg){
  console.log(msg); // 'hello world'
});

对象工厂

在addon.cc模式里,你能用C++函数创建并返回一个新的对象,这个对象所包含的msg属性是由createObject()函数传入:

// addon.cc
#include  <node.h>

using namespace v8;

void  CreateObject(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  Local<Object> obj = Object::New(isolate);
  obj->Set(String::NewFromUtf8(isolate, "msg"), args[0]->ToString());

  args.GetReturnValue().Set(obj);
}

void  Init(Handle<Object> exports, Handle<Object> module) {
  NODE_SET_METHOD(module, "exports", CreateObject);
}

NODE_MODULE(addon, Init)

使用JavaScript测试:

// test.js
var addon = require('./build/Release/addon');

var obj1 = addon('hello');
var obj2 = addon('world');
console.log(obj1.msg+' '+obj2.msg); // 'hello world'

工厂模式

这个模式里展示了如何创建并返回一个JavaScript函数,它是由C++函数包装的 :

// addon.cc
#include  <node.h>

using namespace v8;

void  MyFunction(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);
  args.GetReturnValue().Set(String::NewFromUtf8(isolate, "hello world"));
}

void  CreateFunction(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, MyFunction);
  Local<Function> fn = tpl->GetFunction();

  // omit this to make it anonymous
  fn->SetName(String::NewFromUtf8(isolate, "theFunction"));

  args.GetReturnValue().Set(fn);
}

void  Init(Handle<Object> exports, Handle<Object> module) {
  NODE_SET_METHOD(module, "exports", CreateFunction);
}

NODE_MODULE(addon, Init)

测试:

// test.js
var addon = require('./build/Release/addon');

var fn = addon();
console.log(fn()); // 'hello world'

包装C++对象

以下会创建一个C++对象的包装MyObject,这样他就能在JavaScript中用new实例化。首先在addon.cc中准备主要模块:

// addon.cc
#include  <node.h>
#include  "myobject.h"

using namespace v8;

void  InitAll(Handle<Object> exports) {
  MyObject::Init(exports);
}

NODE_MODULE(addon, InitAll)

接着在myobject.h创建包装,它继承自node::ObjectWrap:

// myobject.h
#ifndef MYOBJECT_H
#define MYOBJECT_H

#include  <node.h>
#include  <node_object_wrap.h>

class MyObject : public node::ObjectWrap {
 public:
  static  void  Init(v8::Handle<v8::Object> exports);

 private:
  explicit  MyObject(double value = 0);
  ~MyObject();

  static  void  New(const v8::FunctionCallbackInfo<v8::Value>& args);
  static  void  PlusOne(const v8::FunctionCallbackInfo<v8::Value>& args);
  static v8::Persistent<v8::Function> constructor;
  double value_;
};

#endif

在myobject.cc中实现各种暴露的方法,通过给构造函数添加prototype属性来暴露plusOne方法:

// myobject.cc
#include "myobject.h"

using namespace v8;

Persistent<Function> MyObject::constructor;

MyObject::MyObject(double value) : value_(value) {
}

MyObject::~MyObject() {
}

void MyObject::Init(Handle<Object> exports) {
  Isolate* isolate = Isolate::GetCurrent();

  // Prepare constructor template
  Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
  tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  // Prototype
  NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne);

  constructor.Reset(isolate, tpl->GetFunction());
  exports->Set(String::NewFromUtf8(isolate, "MyObject"),
               tpl->GetFunction());
}

void MyObject::New(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  if (args.IsConstructCall()) {
    // Invoked as constructor: `new MyObject(...)`
    double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
    MyObject* obj = new MyObject(value);
    obj->Wrap(args.This());
    args.GetReturnValue().Set(args.This());
  } else {
    // Invoked as plain function `MyObject(...)`, turn into construct call.
    const int argc = 1;
    Local<Value> argv[argc] = { args[0] };
    Local<Function> cons = Local<Function>::New(isolate, constructor);
    args.GetReturnValue().Set(cons->NewInstance(argc, argv));
  }
}

void MyObject::PlusOne(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.Holder());
  obj->value_ += 1;

  args.GetReturnValue().Set(Number::New(isolate, obj->value_));
}

测试:

// test.js
var addon = require('./build/Release/addon');

var obj = new addon.MyObject(10);
console.log( obj.plusOne() ); // 11
console.log( obj.plusOne() ); // 12
console.log( obj.plusOne() ); // 13

包装对象工厂

当你想创建本地对象,又不想在JavaScript中严格的使用new初始化的时候,以下方法非常实用:

var obj = addon.createObject();
// instead of:
// var obj = new addon.Object();

addon.cc中注册createObject方法:

// addon.cc
#include  <node.h>
#include  "myobject.h"

using namespace v8;

void  CreateObject(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);
  MyObject::NewInstance(args);
}

void  InitAll(Handle<Object> exports, Handle<Object> module) {
  MyObject::Init();

  NODE_SET_METHOD(module, "exports", CreateObject);
}

NODE_MODULE(addon, InitAll)

在myobject.h中有静态方法NewInstance,他能实例化对象(它就像JavaScript的new):

// myobject.h
#ifndef MYOBJECT_H
#define MYOBJECT_H

#include  <node.h>
#include  <node_object_wrap.h>

class MyObject : public node::ObjectWrap {
 public:
  static  void  Init();
  static  void  NewInstance(const v8::FunctionCallbackInfo<v8::Value>& args);

 private:
  explicit  MyObject(double value = 0);
  ~MyObject();

  static  void  New(const v8::FunctionCallbackInfo<v8::Value>& args);
  static  void  PlusOne(const v8::FunctionCallbackInfo<v8::Value>& args);
  static v8::Persistent<v8::Function> constructor;
  double value_;
};

#endif

这个实现方法和myobject.cc类似:

// myobject.cc
#include <node.h>
#include "myobject.h"

using namespace v8;

Persistent<Function> MyObject::constructor;

MyObject::MyObject(double value) : value_(value) {
}

MyObject::~MyObject() {
}

void MyObject::Init() {
  Isolate* isolate = Isolate::GetCurrent();
  // Prepare constructor template
  Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
  tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  // Prototype
  NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne);

  constructor.Reset(isolate, tpl->GetFunction());
}

void MyObject::New(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  if (args.IsConstructCall()) {
    // Invoked as constructor: `new MyObject(...)`
    double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
    MyObject* obj = new MyObject(value);
    obj->Wrap(args.This());
    args.GetReturnValue().Set(args.This());
  } else {
    // Invoked as plain function `MyObject(...)`, turn into construct call.
    const int argc = 1;
    Local<Value> argv[argc] = { args[0] };
    Local<Function> cons = Local<Function>::New(isolate, constructor);
    args.GetReturnValue().Set(cons->NewInstance(argc, argv));
  }
}

void MyObject::NewInstance(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  const unsigned argc = 1;
  Handle<Value> argv[argc] = { args[0] };
  Local<Function> cons = Local<Function>::New(isolate, constructor);
  Local<Object> instance = cons->NewInstance(argc, argv);

  args.GetReturnValue().Set(instance);
}

void MyObject::PlusOne(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.Holder());
  obj->value_ += 1;

  args.GetReturnValue().Set(Number::New(isolate, obj->value_));
}

测试:

// test.js
var createObject = require('./build/Release/addon');

var obj = createObject(10);
console.log( obj.plusOne() ); // 11
console.log( obj.plusOne() ); // 12
console.log( obj.plusOne() ); // 13

var obj2 = createObject(20);
console.log( obj2.plusOne() ); // 21
console.log( obj2.plusOne() ); // 22
console.log( obj2.plusOne() ); // 23

传递包装对象

除了包装并返回C++对象,你可以使用Node的node::ObjectWrap::Unwrap帮助函数来解包。在下面的addon.cc中,我们介绍了一个add()函数,它能获取2个 MyObject对象:

// addon.cc
#include  <node.h>
#include  <node_object_wrap.h>
#include  "myobject.h"

using namespace v8;

void  CreateObject(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);
  MyObject::NewInstance(args);
}

void  Add(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  MyObject* obj1 = node::ObjectWrap::Unwrap<MyObject>(
      args[0]->ToObject());
  MyObject* obj2 = node::ObjectWrap::Unwrap<MyObject>(
      args[1]->ToObject());

  double sum = obj1->value() + obj2->value();
  args.GetReturnValue().Set(Number::New(isolate, sum));
}

void  InitAll(Handle<Object> exports) {
  MyObject::Init();

  NODE_SET_METHOD(exports, "createObject", CreateObject);
  NODE_SET_METHOD(exports, "add", Add);
}

NODE_MODULE(addon, InitAll)

介绍myobject.h里的一个公开方法,它能在解包后使用私有变量:

// myobject.h
#ifndef MYOBJECT_H
#define MYOBJECT_H

#include  <node.h>
#include  <node_object_wrap.h>

class MyObject : public node::ObjectWrap {
 public:
  static  void  Init();
  static  void  NewInstance(const v8::FunctionCallbackInfo<v8::Value>& args);
  inline  double  value()  const { return value_; }

 private:
  explicit  MyObject(double value = 0);
  ~MyObject();

  static  void  New(const v8::FunctionCallbackInfo<v8::Value>& args);
  static v8::Persistent<v8::Function> constructor;
  double value_;
};

#endif

myobject.cc的实现方法和之前的类似:

// myobject.cc
#include <node.h>
#include "myobject.h"

using namespace v8;

Persistent<Function> MyObject::constructor;

MyObject::MyObject(double value) : value_(value) {
}

MyObject::~MyObject() {
}

void MyObject::Init() {
  Isolate* isolate = Isolate::GetCurrent();

  // Prepare constructor template
  Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
  tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  constructor.Reset(isolate, tpl->GetFunction());
}

void MyObject::New(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  if (args.IsConstructCall()) {
    // Invoked as constructor: `new MyObject(...)`
    double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
    MyObject* obj = new MyObject(value);
    obj->Wrap(args.This());
    args.GetReturnValue().Set(args.This());
  } else {
    // Invoked as plain function `MyObject(...)`, turn into construct call.
    const int argc = 1;
    Local<Value> argv[argc] = { args[0] };
    Local<Function> cons = Local<Function>::New(isolate, constructor);
    args.GetReturnValue().Set(cons->NewInstance(argc, argv));
  }
}

void MyObject::NewInstance(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  const unsigned argc = 1;
  Handle<Value> argv[argc] = { args[0] };
  Local<Function> cons = Local<Function>::New(isolate, constructor);
  Local<Object> instance = cons->NewInstance(argc, argv);

  args.GetReturnValue().Set(instance);
}

测试:

// test.js
var addon = require('./build/Release/addon');

var obj1 = addon.createObject(10);
var obj2 = addon.createObject(20);
var result = addon.add(obj1, obj2);

console.log(result); // 30
由JSRUN为你提供的JS在线运行、在线编译工具
        JSRUN提供的JS 在线运行,JS 在线运行工具,基于linux操作系统环境提供线上编译和线上运行,具有运行快速,运行结果与常用开发、生产环境保持一致的特点。
yout