什么是 "[native code]"?——JavaScript中的原生代码
1090字约4分钟
2025-01-16
在使用 JavaScript 进行开发时,你可能会经常看到一些函数或方法的源代码输出以 [native code]
结尾。那么这个术语究竟是什么意思呢?本文将深入探讨 [native code]
的含义,并为读者提供有关如何编写原生 JavaScript 代码的指导。
什么是 “[native code]”?
在 JavaScript 中,一个函数可以用两种方式定义:一种是使用 JavaScript 代码直接定义,另一种则是通过绑定到 JavaScript 引擎的底层 C 或 C++ 代码实现的。如果函数是由底层代码实现的,那么在调试器中查看其源代码时,就会显示 [native code]
。
底层代码通常是由浏览器厂商编写的,因此具有高度优化的性能和功能。例如,Array.prototype.push()
和 Array.prototype.pop()
等方法就是由底层代码实现的。而在 JavaScript 引擎中运行的其他代码,则是由 JavaScript 解释器解释执行。
值得注意的是,对于底层代码实现的函数,虽然无法查看其源代码,但它们仍然遵循了相同的规则和语法,即可通过 JavaScript 代码进行调用和使用。
如何编写原生 JavaScript 代码?
1. 原生模块的定义
Node.js 支持使用 C 或 C++ 编写原生模块,这些模块可以直接调用系统级别的 API,从而实现更高效的性能和更强的功能。编写原生模块的主要步骤包括编写 C/C++ 代码、使用 node-gyp
编译模块、在 Node.js 中加载模块。
2. 环境搭建与基础代码编写
首先,确保你的开发环境中已安装了 node-gyp
,可以通过以下命令安装:
npm install -g node-gyp
接下来,创建一个新的 Node.js 项目,并初始化:
mkdir my-native-module
cd my-native-module
npm init -y
然后,创建一个包含基本 C++ 代码的文件 my_module.cc
:
#include <node.h>
namespace demo {
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::String;
using v8::Value;
void Method(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
args.GetReturnValue().Set(String::NewFromUtf8(isolate, "Hello, world!").ToLocalChecked());
}
void Initialize(Local<Object> exports) {
NODE_SET_METHOD(exports, "hello", Method);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)
} // namespace demo
3. 使用 node-gyp 编译模块
在项目根目录下创建一个 binding.gyp
文件,内容如下:
{
"targets": [
{
"target_name": "my_module",
"sources": ["my_module.cc"]
}
]
}
然后运行以下命令来编译模块:
node-gyp configure
node-gyp build
4. 在 Node.js 中加载原生模块
现在可以在 Node.js 中使用这个原生模块了:
const myModule = require('./build/Release/my_module');
console.log(myModule.hello()); // 输出: Hello, world!
利用 N-API 接口编写原生模块
1. N-API 的定义
N-API 是 Node.js 提供的一组 API,用于创建和操作 Node.js 对象。使用 N-API 可以编写与 V8 引擎无关的原生模块,从而提高模块的兼容性。
2 编写 N-API 模块
首先,创建一个包含基本 N-API 代码的文件 my_napi_module.cc
:
#include <node_api.h>
napi_value Method(napi_env env, napi_callback_info args) {
napi_value greeting;
napi_create_string_utf8(env, "Hello, world!", NAPI_AUTO_LENGTH, &greeting);
return greeting;
}
napi_value Init(napi_env env, napi_value exports) {
napi_value fn;
napi_create_function(env, nullptr, 0, Method, nullptr, &fn);
napi_set_named_property(env, exports, "hello", fn);
return exports;
}
NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)
3. 使用 node-gyp 编译 N-API 模块
与上面的方法类似,创建一个 binding.gyp
文件:
{
"targets": [
{
"target_name": "my_napi_module",
"sources": ["my_napi_module.cc"]
}
]
}
然后运行以下命令来编译模块:
node-gyp configure
node-gyp build
4. Node.js 中加载 N-API 模块
现在可以在 Node.js 中使用这个 N-API 模块了:
const myNapiModule = require('./build/Release/my_napi_module');
console.log(myNapiModule.hello()); // 输出: Hello, world!
使用 FFI 库编写原生模块
1 FFI 的定义
FFI(Foreign Function Interface)是一个允许程序调用其他编程语言函数的机制。Node.js 中可以使用 ffi-napi
库来调用 C 函数。
2 安装 ffi-napi 库
首先,安装 ffi-napi
和 ref-napi
库:
npm install ffi-napi ref-napi
编写 C 代码并生成共享库
创建一个包含基本 C 代码的文件 my_library.c
:
#include <stdio.h>
void print_hello() {
printf("Hello, world!\n");
}
然后编译生成共享库:
gcc -shared -o my_library.so my_library.c
3. Node.js 中加载 FFI 模块
在 Node.js 中使用 ffi-napi 库调用 C 函数:
const ffi = require('ffi-napi');
const ref = require('ref-napi');
// 定义共享库和函数
const myLibrary = ffi.Library('my_library', {
print_hello: ['void', []]
})
// 调用函数
myLibrary.print_hello(); // 输出: Hello, world!