如何将其正确绑定到 Javascript 中的 getter/setter

Per*_*lle 5 javascript bind getter-setter defineproperty

假设我有一个类将其实例的属性存储在嵌套对象中:

this.Properties = {
  "Position":{
    "X": 400,
    "Y": 100
  },
  "Colour": "#007fff7f"
};
Run Code Online (Sandbox Code Playgroud)

我想为每个(嵌套的)属性定义特殊的 getter/setter,以便我可以添加范围检查/自动更新特定于实例的 HTML 元素的属性等。当我用普通方法尝试它时,我意识到我无法将范围绑定到 getter/setter 中的参数:

//(based on /sf/answers/1148043851/)
//Define function prototype for binding an argument without overriding the old this:
Function.prototype.BindArgs = function(...boundArgs){
  const targetFunction = this;
  return function (...args) { return targetFunction.call(this, ...boundArgs, ...args); };
};

//...

{
  get X(){
    return this.__X__;
  },
  set X(Scope, Value){
    this.__X__ = Value;
    Scope.HTMLElement.style.left = Value + "px";
  }.BindArgs(this)  //This is incorrect syntax
}
Run Code Online (Sandbox Code Playgroud)

上面的代码没有运行:不是因为 BindArgs 是一个无效的原型,而是它不起作用,因为setter 实际上不是一个函数答案建议使用 Object.defineProperty,它实际上有效:

Object.defineProperty(this.Properties.Position, "X", {
  "get": function(){
    return this.__X__;
  }
  "set": function(Scope, Value){
    this.__X__ = Value;
    Scope.HTMLElement.style.left = Value + "px";
  }.BindArgs(this)
});
Run Code Online (Sandbox Code Playgroud)

现在,当我有一些像上面例子中的属性时,这会很好,但是必须为几十个属性这样做变得非常乏味——尤其是对于嵌套属性。是否有另一种更简洁的方式来定义自定义 getter/setter 并能够将参数绑定到它们?正常语法本来是理想的,因为它都在对象定义内部,而不是像 Object.defineProperty 那样分散。显而易见的答案是使用普通函数来获取/设置值,但这样做意味着必须重构大量代码......

Kla*_*con 4

我建议您使用代理进行验证。它只需要很少的代码更改,并且您可以一次性处理多个属性。

let validator = {
  set: function(obj, prop, value) {
    //in any of these cases you can return false or throw an error to refuse the new value
    switch(prop) {
      case "X":
        Scope.HTMLElement.style.left = value + "px";
        break;
      case "Y":
        Scope.HTMLElement.style.top = value + "px";
        break;
      case "Colour":
        Scope.HTMLElement.style.color = value;
    }

    obj[prop] = value;

    return true;
  }
};

this.Properties.Position = new Proxy(this.Properties.Position, validator);
this.Properties = new Proxy(this.Properties, validator);
Run Code Online (Sandbox Code Playgroud)

请注意,这使用了快捷方式(Properties和 都使用相同的验证器Properties.Position),如果您发现属性名称可能重叠,则可能需要多个validator对象。