JS在线运行

版本:
运行结果
教程手册
代码仓库
极速运行
交互输入
极速运行模式,更高效的运行,点击编辑器上方的运行按钮即刻体验吧。
以下是用户最新保存的代码
生成激活码 发布于:2022-10-03 17:14 递归和堆栈 发布于:2022-10-03 11:27 nodejs function 发布于:2022-09-28 10:52 Promise 高级考核;不计原理,计原理产生的效果;原理太懵逼; 发布于:2022-09-24 20:23 测试 grok-js 发布于:2022-09-23 15:14 获取案件服务人员分支机构、部门信息 发布于:2022-09-22 14:06 将平行结构数据转为树形结构 发布于:2022-09-22 09:19 js 获取 url 的某个参数 发布于:2022-09-21 16:26 股票报价js 发布于:2022-09-20 18:05 JS call()方法 发布于:2022-09-20 14:46 JS 深拷贝 发布于:2022-09-20 14:26 测试Vue-Quill-Editor 发布于:2022-09-20 14:11 员工排序js版 发布于:2022-09-19 16:09 给你一个字符串 s,请你返回 两个相同字符之间的最长子字符串的长度 ,计算长度时不含这两个字符。如果不存在这样的子字符串,返回 -1 。 子字符串 是字符串中的一个连续字符序列。 发布于:2022-09-28 11:16 看代码说出运行结果 发布于:2022-09-17 09:48 哔哩哔哩密码逆向 发布于:2022-09-16 21:16 临时数据处理 发布于:2022-09-16 16:18 实现一个插入排序 发布于:2022-09-16 00:16 手动实现一个Array的sort 发布于:2022-09-16 00:01 给你一个整数数组 arr ,请你删除最小 5% 的数字和最大 5% 的数字后,剩余数字的平均值。 与 标准答案 误差在 10-5 的结果都被视为正确结果。 发布于:2022-09-15 17:14 // 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数, // 并返回它们的数组下标。 发布于:2022-09-15 17:01 实现一个控制并发的Scheduler调度器 addTask(1000,"1"); addTask(500,"2"); addTask(300,"3"); addTask(400,"4"); 的输出顺序是:2 3 1 4 整个的完整执行流程: 一开始1、2两个任务开始执行 500ms时,2任务执行完毕,输出2,任务3开始执行 800ms时,3任务执行完毕,输出3,任务4开始执行 1000ms时,1任务执行完毕,输出1,此时只剩下4任务在执行 1200ms时,4任务执行完毕,输出4 发布于:2022-09-15 16:50 测试一些JS知识点 发布于:2022-09-15 13:36 trans(123456) —— 十二万三千四百五十六 trans(100010001)—— 一亿零一万零一 发布于:2022-09-15 16:15 根据项目业务需求,进行以下两种格式的互相转换 例如 let arr=[1,2,3,4,5] let arr2=null let arr3 = ['a','b'] format_data({q:arr,w:arr2,e:arr3}) [ { q: 1, w: null, e: 'a' }, { q: 2, w: null, e: 'b' }, { q: 3, w: null, e: null }, { q: 4, w: null, e: null }, { q: 5, w: null, e: null } ] 发布于:2022-09-14 14:36 防抖和节流 发布于:2022-09-13 11:06 递归实现斐波那契数列 发布于:2022-09-12 17:41 反直觉 数组操作 发布于:2022-09-11 11:21 数组所有组合的算法 发布于:2022-09-11 10:01 复选框全选与取消 发布于:2022-09-09 23:43 让对象按数组迭代 发布于:2022-09-09 16:54 使用JS实现一个单链表的类 发布于:2022-09-09 15:44 找出字符串中出现次数最多的字符及次数 发布于:2022-09-09 12:03 字符串中a出现的位置及次数 发布于:2022-09-09 11:46 js数组去重 发布于:2022-09-09 11:29 斐波那契数列 // F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2) 斐波那契数列的memoization优化 发布于:2022-09-14 17:23 扁平数组转tree 发布于:2022-09-08 15:29 扁平数据转为tree(只能处理一层) 发布于:2022-09-08 14:56 封装localStorage 发布于:2022-09-08 14:46 jq.on原理实现 发布于:2022-09-07 00:42 实现一个对象拍平 发布于:2022-09-06 00:27 使用proxy实现一个对象属性的双向绑定 发布于:2022-09-05 17:17 遍历一次将扁平数据转为tree 发布于:2022-09-05 19:02 this指向,手写bind、call、apply、new 发布于:2022-09-04 21:07 字符串是有括号组成,判断内容是否为有效内容 发布于:2022-09-04 00:29 自己实现一个new 发布于:2022-09-03 17:09 使用renduce实现一个map、filter 发布于:2022-09-03 12:06 Js 使用reduce实现一个map 发布于:2022-09-02 00:12 JS实现一个观察者模式 发布于:2022-09-02 00:07 学习倾国每日答题多选题 发布于:2022-09-01 18:29 [更多]
显示目录

C/C++ 插件



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操作系统环境提供线上编译和线上运行,具有运行快速,运行结果与常用开发、生产环境保持一致的特点。

title

使用此草稿 删除草稿

  • 00:23
注册登录后可减少验证码的弹出,点击前往 注册 | 登录

皮肤:

运行模式:

嵌入代码 iframe嵌入:


服务器已安装大部分常用的第依赖库,但仍可能存在一些未被安装的库, 可以通过本窗口立即安装所需依赖库。


请输入依赖库的名称:

请选择语言: