如何使 Google V8 Javascript 引擎中的对象不可变?
How can I make an object immutable in the Google V8 Javascript engine?
是否可以在 V8 Javascript 引擎中使对象不可变? V8 嵌入到 C++ 应用程序中。
在我的例子中,我创建并填充了一个数组 (代码已简化)
auto arr = v8::Array::New(isolate, 10);
for (auto i = 0; i < 10; ++i)
{
arr->Set(context, i, v8::Integer::New(isolate, i));
}
我想在将结果对象传递给脚本之前生成 "read-only"(您可能会通过调用 Object.freeze 获得)。我的一位脚本作者试图重新使用此对象是一种令人费解的方式,这使他们自己陷入了混乱的境地,我想通过使对象不可变来使这种情况更难发生。
我知道我可以在 Javascript (Object.freeze) 中执行此操作,但如果可能的话,我希望能够在 C++ 中执行此操作。
这种方法有效,尽管有点不雅。本质上,我是在 Javascript 中直接调用 "Object.freeze",因为我找不到从 C++ 调用此功能的方法。我不太熟悉 V8,所以我的代码可能不必要地冗长。
/**
* Make an object immutable by calling "Object.freeze".
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze
**/
void ezv8::utility::MakeImmutable(v8::Isolate * isolate, v8::Local<v8::Object> object)
{
ezv8::Ezv8 ezv8(isolate);
auto globalTmpl = v8::ObjectTemplate::New(isolate);
auto context = v8::Context::New(isolate, nullptr, globalTmpl);
v8::Isolate::Scope scope(isolate);
v8::Locker locker(isolate);
v8::HandleScope scope(ezv8.getIsolate());
v8::Context::Scope context_scope(context);
// Define function "deepFreeze" as listed on the "Object.freeze" documentation page cited above.
std::string code(
"function deepFreeze(obj) {\n"
" var propNames = Object.getOwnPropertyNames(obj);\n"
" propNames.forEach(function(name) {\n"
" var prop = obj[name];\n"
" if (typeof prop == 'object' && prop !== null)\n"
" deepFreeze(prop);\n"
" });\n"
" return Object.freeze(obj);\n"
"};");
v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, code.c_str());
v8::Local<v8::Script> compiled_script(v8::Script::Compile(source));
// Run the script!
v8::Local<v8::Value> result = compiled_script->Run();
v8::Handle<v8::Value> argv[]{ object };
v8::Handle<v8::String> process_name = v8::String::NewFromUtf8(isolate, "deepFreeze");
v8::Handle<v8::Value> process_val = context->Global()->Get(process_name);
v8::Handle<v8::Function> process_fun = v8::Handle<v8::Function>::Cast(process_val);
v8::Local<v8::Function> process = v8::Local<v8::Function>::New(isolate, process_fun);
// Call the script.
v8::Local<v8::Value> rv = process->Call(context->Global(), 1, argv);
}
是否可以在 V8 Javascript 引擎中使对象不可变? V8 嵌入到 C++ 应用程序中。
在我的例子中,我创建并填充了一个数组 (代码已简化)
auto arr = v8::Array::New(isolate, 10);
for (auto i = 0; i < 10; ++i)
{
arr->Set(context, i, v8::Integer::New(isolate, i));
}
我想在将结果对象传递给脚本之前生成 "read-only"(您可能会通过调用 Object.freeze 获得)。我的一位脚本作者试图重新使用此对象是一种令人费解的方式,这使他们自己陷入了混乱的境地,我想通过使对象不可变来使这种情况更难发生。
我知道我可以在 Javascript (Object.freeze) 中执行此操作,但如果可能的话,我希望能够在 C++ 中执行此操作。
这种方法有效,尽管有点不雅。本质上,我是在 Javascript 中直接调用 "Object.freeze",因为我找不到从 C++ 调用此功能的方法。我不太熟悉 V8,所以我的代码可能不必要地冗长。
/**
* Make an object immutable by calling "Object.freeze".
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze
**/
void ezv8::utility::MakeImmutable(v8::Isolate * isolate, v8::Local<v8::Object> object)
{
ezv8::Ezv8 ezv8(isolate);
auto globalTmpl = v8::ObjectTemplate::New(isolate);
auto context = v8::Context::New(isolate, nullptr, globalTmpl);
v8::Isolate::Scope scope(isolate);
v8::Locker locker(isolate);
v8::HandleScope scope(ezv8.getIsolate());
v8::Context::Scope context_scope(context);
// Define function "deepFreeze" as listed on the "Object.freeze" documentation page cited above.
std::string code(
"function deepFreeze(obj) {\n"
" var propNames = Object.getOwnPropertyNames(obj);\n"
" propNames.forEach(function(name) {\n"
" var prop = obj[name];\n"
" if (typeof prop == 'object' && prop !== null)\n"
" deepFreeze(prop);\n"
" });\n"
" return Object.freeze(obj);\n"
"};");
v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, code.c_str());
v8::Local<v8::Script> compiled_script(v8::Script::Compile(source));
// Run the script!
v8::Local<v8::Value> result = compiled_script->Run();
v8::Handle<v8::Value> argv[]{ object };
v8::Handle<v8::String> process_name = v8::String::NewFromUtf8(isolate, "deepFreeze");
v8::Handle<v8::Value> process_val = context->Global()->Get(process_name);
v8::Handle<v8::Function> process_fun = v8::Handle<v8::Function>::Cast(process_val);
v8::Local<v8::Function> process = v8::Local<v8::Function>::New(isolate, process_fun);
// Call the script.
v8::Local<v8::Value> rv = process->Call(context->Global(), 1, argv);
}