如何用较新的 V8 API 编写 setter?

How to write a setter with newer V8 API?

V8 embedding guide in the section for accessing dynamic variables, it describes how to write a setter for a wrapped C++ object. But the documentation seems to have rotted a bit in its usage of ToInt32 compared to the current (v14.1) API.

这个例子...

void SetPointX(v8::Local<v8::String> property, v8::Local<v8::Value> value,
               const v8::PropertyCallbackInfo<void>& info) {
  v8::Local<v8::Object> self = info.Holder();
  v8::Local<v8::External> wrap =
      v8::Local<v8::External>::Cast(self->GetInternalField(0));
  void* ptr = wrap->Value();
  static_cast<Point*>(ptr)->x_ = value->Int32Value();
}

...调用 v8::Local<v8::Value>::Int32Value() 但不再存在返回可以转换为 int 的内容的无参数重载。在当前 API 中,该函数需要一个 v8::Local<v8::Context> 参数,并且 returns 需要一个 v8::Maybe<int32_t>.

如何修改此 SetPointX 函数以访问 Context 并处理 ToInt32 returns 的 Maybe

对于 Context:最好跟踪要使用的正确上下文。如果你只有一个,那很简单:-) 只需在创建它时将其存储在 v8::Persistent 中,并在需要时从中创建一个 v8::Local<v8::Context>。如果您碰巧有多个上下文,您会(希望)欣赏这为您提供的控制量——对于需要关心此类事情的应用程序,排除与安全相关的跨上下文访问尤其重要。

对于Maybe<int32_t>:检查是否为Nothing,如果是则处理错误。

// On initialization:
v8::Isolate* isolate = ...;
v8::Persistent context(v8::Context::New(isolate));

// And then later:
v8::Maybe<int32_t> maybe_value = value->Int32Value(context.Get(isolate));

// Alternative 1 (more elegant, can inline `maybe_value`):
int32_t int_value;
if (!maybe_value.To(&value)) {
  // Handle exception and return.
}

// Alternative 2 (easier to follow):
if (maybe_value.IsNothing()) {
  // Handle exception and return.
}
int32_t int_value = maybe_value.FromJust();  // Crashes if maybe_value.IsNothing()

static_cast<Point*>(ptr)->x_ = int_value;

之所以需要 Maybe 舞蹈是因为 JavaScript 代码如下:

my_point.x = {valueOf: () => throw "this is why we can't have nice things"; }

旧版本 value->Int32Value() 在尝试获取 int32 值时无法发出异常抛出信号。当然,这不仅适用于此类人工示例,还适用于堆栈溢出或 ReferenceErrors 等其他异常