You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Node.js C++ Addon引用JavaScript原始值?

可以借助Node.js C++ Addon实现引用JS原始值的需求

JS原始值(如number、string)本身是不可变且按值传递的,无法直接创建引用,但可以通过C++ Addon创建包装/代理对象来模拟引用效果,让两个变量共享同一个可变的值容器。以下是具体实现步骤:

1. 准备开发环境

确保已安装:

  • Node.js(版本>=12)
  • node-gyp(全局安装:npm install -g node-gyp)
  • 对应平台的C编译工具链(Windows需安装Visual Studio,macOS需安装Xcode Command Line Tools,Linux需安装gcc/g)

2. 编写Addon配置文件(binding.gyp)

创建binding.gyp文件,用于告诉node-gyp如何编译Addon:

{
  "targets": [
    {
      "target_name": "mymodule",
      "sources": ["mymodule.cc"],
      "include_dirs": ["<!(node -p \"require('node-addon-api').include\")"],
      "dependencies": ["<!(node -p \"require('node-addon-api').gyp\")"],
      "cflags!": ["-fno-exceptions"],
      "cflags_cc!": ["-fno-exceptions"]
    }
  ]
}

3. 编写C++ Addon代码(mymodule.cc)

使用N-API(跨Node版本稳定的API)实现一个可变值包装对象,提供ref方法返回包装对象:

#include <napi.h>

// 自定义包装类,持有可变的JS值
class ValueRef : public Napi::ObjectWrap<ValueRef> {
public:
  static Napi::Object Init(Napi::Env env, Napi::Object exports) {
    Napi::Function func = DefineClass(env, "ValueRef", {
      InstanceAccessor<&ValueRef::GetValue, &ValueRef::SetValue>("value"),
      InstanceMethod("valueOf", &ValueRef::ValueOf),
      InstanceMethod("toString", &ValueRef::ToString)
    });

    Napi::FunctionReference* constructor = new Napi::FunctionReference();
    *constructor = Napi::Persistent(func);
    env.SetInstanceData(constructor);

    exports.Set("ValueRef", func);
    return exports;
  }

  explicit ValueRef(const Napi::CallbackInfo& info) : Napi::ObjectWrap<ValueRef>(info) {
    Napi::Env env = info.Env();
    if (info.Length() < 1) {
      Napi::TypeError::New(env, "Expected an initial value").ThrowAsJavaScriptException();
      return;
    }
    // 保存初始值
    _value = info[0];
  }

  // 获取内部值
  Napi::Value GetValue(const Napi::CallbackInfo& info) {
    return _value;
  }

  // 设置内部值
  void SetValue(const Napi::CallbackInfo& info, const Napi::Value& value) {
    _value = value;
  }

  // 实现valueOf,让对象在数值运算时自动拆箱
  Napi::Value ValueOf(const Napi::CallbackInfo& info) {
    return _value;
  }

  // 实现toString,让console.log时显示值
  Napi::Value ToString(const Napi::CallbackInfo& info) {
    return _value.ToString();
  }

private:
  Napi::Value _value;
};

// 暴露给JS的ref函数
Napi::Value Ref(const Napi::CallbackInfo& info) {
  Napi::Env env = info.Env();
  if (info.Length() < 1) {
    Napi::TypeError::New(env, "Expected a value to reference").ThrowAsJavaScriptException();
    return env.Undefined();
  }
  // 创建ValueRef实例,传入初始值
  Napi::FunctionReference* constructor = env.GetInstanceData<Napi::FunctionReference>();
  return constructor->New({info[0]});
}

// 模块初始化函数
Napi::Object Init(Napi::Env env, Napi::Object exports) {
  ValueRef::Init(env, exports);
  exports.Set("ref", Napi::Function::New(env, Ref));
  return exports;
}

NODE_API_MODULE(mymodule, Init)

4. 编译Addon

在项目目录下执行:

node-gyp configure build

编译完成后,会在build/Release目录生成mymodule.node文件。

5. 测试使用

修改测试代码为符合实际实现的版本(因为JS原始值无法直接引用,需通过包装对象的属性修改):

let addon = require('./build/Release/mymodule.node')
let numObj = addon.ref(999)
// 修改包装对象的value属性
numObj.value++

console.log(numObj.value) // 输出1000
console.log(numObj) // 输出1000(因实现了toString方法)
// 数值运算时自动拆箱
console.log(numObj + 1) // 输出1001

如果想要更贴近你示例的写法,可以结合JS的Proxy来拦截变量赋值,模拟原始变量的语法:

let addon = require('./build/Release/mymodule.node')
let numObj = addon.ref(999)
// 创建Proxy模拟原始变量的写法
let num1 = new Proxy(numObj, {
  get(target, prop) {
    if (prop === 'valueOf') return () => target.value
    if (prop === Symbol.toPrimitive) return () => target.value
    return target[prop]
  },
  set(target, prop, value) {
    if (prop === 'value') {
      target.value = value
      return true
    }
    return false
  }
})

num1++
console.log(num1) // 输出1000
console.log(numObj.value) // 输出1000

原理说明

  • JS原始值不可变且按值传递,所以我们用C++ Addon创建一个可变的包装对象,内部持有原始值的副本,所有修改操作都是针对这个对象的内部值。
  • 通过实现valueOf和toString方法,让包装对象在数值运算或打印时自动拆箱,模拟原始值的行为。
  • 若要完全模拟原始变量的赋值语法,可以结合JS Proxy拦截赋值操作,将赋值转发给包装对象的内部值。

内容的提问来源于stack exchange,提问作者Time Killer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 13:52:22