이것을 Javascript의 getter / setter에 올바르게 바인딩하는 방법

Aug 25 2020

인스턴스의 속성을 중첩 된 개체에 저장하는 클래스가 있다고 가정 해 보겠습니다.

this.Properties = {
  "Position":{
    "X": 400,
    "Y": 100
  },
  "Colour": "#007fff7f"
};

범위 검사를 추가하거나 인스턴스 별 HTML 요소의 속성을 자동으로 업데이트 할 수 있도록 각 (중첩 된) 속성에 대해 특별한 getter / setter를 정의하고 싶었습니다. 일반적인 방법으로 시도했을 때 getter / setter의 인수에 범위를 바인딩 할 수 없습니다.

//(based on https://stackoverflow.com/a/16400626)
//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
}

위 코드는 실행되지 않습니다. 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)
});

이제 위의 예에서와 같은 속성이 몇 개 있으면 괜찮지 만 수십 개의 속성에 대해이 작업을 수행해야하는 것은 특히 중첩 속성의 경우 매우 지루합니다. 사용자 지정 getter / setter를 정의하고 인수를 바인딩 할 수있는 또 다른 깔끔한 방법이 있습니까? 일반 구문은 모두 객체 정의 내부에 있고 Object.defineProperty처럼 흩어져 있지 않기 때문에 이상적이었을 것입니다. 분명한 대답은 일반 함수를 사용하여 값을 가져 오거나 설정하는 것이지만 그렇게하려면 많은 코드를 리팩터링해야합니다.

답변

4 Klaycon Aug 25 2020 at 00:31

검증 을 위해 프록시를 사용하는 것이 좋습니다 . 최소한의 코드 변경이 필요하며 한 번에 여러 속성을 처리 할 수 ​​있습니다.

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);

이것은 바로 가기 ( Properties및 둘 다에 대해 동일한 유효성 검사기 Properties.Position)를 사용합니다. 속성 이름이 겹치는 경우 여러 validator개체 가 필요할 수 있습니다.