SetAccessor 和 SetAccessorProperty,有什么区别吗?

SetAccessor and SetAccessorProperty, any difference?

V8 的 ObjectTemplate 为我们提供了两种方法来将所谓的访问器 属性 附加到实例化的对象。 第一个是 ObjectTemplate::SetAccessor:

/**
   * Sets an accessor on the object template.
   *
   * Whenever the property with the given name is accessed on objects
   * created from this ObjectTemplate the getter and setter callbacks
   * are called instead of getting and setting the property directly
   * on the JavaScript object.
   *
   * \param name The name of the property for which an accessor is added.
   * \param getter The callback to invoke when getting the property.
   * \param setter The callback to invoke when setting the property.
   * \param data A piece of data that will be passed to the getter and setter
   *   callbacks whenever they are invoked.
   * \param settings Access control settings for the accessor. This is a bit
   *   field consisting of one of more of
   *   DEFAULT = 0, ALL_CAN_READ = 1, or ALL_CAN_WRITE = 2.
   *   The default is to not allow cross-context access.
   *   ALL_CAN_READ means that all cross-context reads are allowed.
   *   ALL_CAN_WRITE means that all cross-context writes are allowed.
   *   The combination ALL_CAN_READ | ALL_CAN_WRITE can be used to allow all
   *   cross-context access.
   * \param attribute The attributes of the property for which an accessor
   *   is added.
   * \param signature The signature describes valid receivers for the accessor
   *   and is used to perform implicit instance checks against them. If the
   *   receiver is incompatible (i.e. is not an instance of the constructor as
   *   defined by FunctionTemplate::HasInstance()), an implicit TypeError is
   *   thrown and no callback is invoked.
   */
  void SetAccessor(
      Local<String> name, AccessorGetterCallback getter,
      AccessorSetterCallback setter = nullptr,
      Local<Value> data = Local<Value>(), AccessControl settings = DEFAULT, // note the data is on the template level.
      PropertyAttribute attribute = None, // not on the instance level.
      Local<AccessorSignature> signature = Local<AccessorSignature>(),
      SideEffectType getter_side_effect_type = SideEffectType::kHasSideEffect,
      SideEffectType setter_side_effect_type = SideEffectType::kHasSideEffect);

第二个是Template::SetAccessorProperty:

void SetAccessorProperty(
     Local<Name> name, // The latter one is called data property.
     Local<FunctionTemplate> getter = Local<FunctionTemplate>(),
     Local<FunctionTemplate> setter = Local<FunctionTemplate>(),
     PropertyAttribute attribute = None,
     AccessControl settings = DEFAULT);

有两个非常相似的 API让我很困惑。 不幸的是,没有 没有 描述它们差异的文档,所以我必须 experiment on my own. I found that the combination of Holder() and SetAccessor() will break, while other combinations of Holder() or This() and SetAccessor() or SetAccessorProperty() work fine. On a previous post 我 运行 进入这个失败的组合并且被愚弄相信出了什么问题 Holder() or This()。但是经过实验我现在认为是SetAccessor出了问题

我的问题是,SetAccessor 是否已弃用 API?如果是这样,我们所要做的就是停止使用它。如果不是这样,请解释一下它们的不同之处,尤其是导致此故障的原因。非常感谢热心和经验丰富的V8开发人员!

我同意名称可能有点混乱;两者都没有被弃用。区别如下:

SetAccessor creates a "magic" data 属性: 它看起来像数据 属性 to JavaScript (getOwnPropertyDescriptor returns {value: ..., ...}),但是当 reading/writing 属性 时,将调用您指定的 C++ 回调。对于内置示例,请考虑 Array.prototype.length(当您使用 .length 赋值来缩短数组时,特别是 setter 必须做额外的工作)。

SetAccessorProperty 创建一个常规访问器 属性,即 getOwnPropertyDescriptor returns {get: ..., set: ..., ...}。一个内置示例是 Int32Array.prototype.__proto__.byteLength。名称 "SetAccessorProperty" 反映了 the JS spec 调用这些属性的事实 "accessor properties".

很可能在许多情况下,这种差异无关紧要:接口 JavaScript 代码可以读取 and/or 写入属性。但有时您可能有理由关心这种区别,在这种情况下,V8 的 API 为您提供了这种灵活性。