2014-01-05 3 views
0

말, 나는 사원 수와 3 축 회전 속성을 모두 가지고있는 3 차원 객체를 구현하는 객체 유형이 있습니다Object.defineProperty를 사용하여 속성간에 양방향 바인딩을 만드는 방법은 무엇입니까?

Object.defineProperty(MyObject3D.prototype, 'rotation', { 
    ... 
}); 

Object.defineProperty(MyObject3D.prototype, 'quaternion', { 
    ... 
}); 

를 내가 때마다 나는 그들, 다른 각을 수정할 수 있는지 확인하려면 속성이 자동으로 다시 계산됩니다. 분명히, 만약 내가 그 속성의 두 가지 메소드를 만들면, 나는 무한 루프로 진행할 것이다.

Object.defineProperty(MyObject3D.prototype, '_rotation', { 
    enumerable: false 
}); 

Object.defineProperty(MyObject3D.prototype, '_quaternion', { 
    enumerable: false 
}); 

Object.defineProperty(MyObject3D.prototype, 'rotation', { 
    get: function() { 
     return this._rotation; 
    }, 
    set: function(r) { 
     this._rotation = r; 
     this._quaternion = rotation2quaternion(r); 
    } 
}); 

Object.defineProperty(MyObject3D.prototype, 'quaternion', { 
    get: function() { 
     return this._rotation; 
    }, 
    set: function(q) { 
     this._quaternion = q; 
     this._rotation= quaternion2rotation(q); 
    } 
}); 
:

지금까지 내가 볼 수있는이 일을하는 유일한 방법은 실제로 (조금 청소기 객체 반성을 위해, 아마 비 열거) 회전 및 사원 수를 닮은 특성의 또 다른 세트를 사용하는 것입니다

더 좋은 방법을 생각해 낼 수 있습니까? 어쩌면 내가 Object.defineProperty 어떤 능력을 누락 더 깨끗하고 짧은 만들 수 있을까? 대신 그들 데이터 속성 수 있도록 간단하고 다음 setRotation 그들을 돌연변이하는 setQuaternion 방법을 정의하지 않을 rotationquaternion 접근 속성을 만드는

답변

2

? 예를 들어 :

function MyObject3D() { 
    ... 
} 

MyObject3D.prototype.setRotation = function (r) { 
    this.quaternion = rotation2quaternion(r); 
    this.rotation = r 
    return this; 
}; 

MyObject3D.prototype.setQuaternion = function (q) { 
    this.rotation = quaternion2rotation(q); 
    this.quaternion = q; 
    return this; 
}; 

이제 .rotation.quaternion 일반적으로 액세스 할 수 있습니다. 그러나 그들을 설정하려면 대신 .setRotation.setQuaternion을 사용하십시오. 예, 사용자가 .rotation.quaternion을 수동으로 설정할 수 있으므로 안전하지 않습니다. 그러나 다음과 같은 장점이 있습니다.

  1. defineProperty을 지원하지 않는 브라우저에서 작동합니다.
  2. this을 반환하므로 작업을 연결할 수 있습니다.
  3. 함수가하는 일을 쉽게 이해할 수 있습니다.

불변의 객체를 사용하는 것이 문제를 해결하는 또 다른 방법. 이것이 하스켈에서하는 방법입니다.

function MyObject3D(rotation, quaternion) { 
    this.quaternion = quaternion; 
    this.rotation = rotation; 
    Object.freeze(this); 
} 

MyObject3D.prototype.putRotation = function (r) { 
    return new MyObject3D(r, rotation2quaternion(r)); 
}; 

MyObject3D.prototype.putQuaternion = function (q) { 
    return new MyObject3D(quaternion2rotation(q), q); 
}; 

당신이 당신의 생성자에서 일부 초기화 로직이있는 경우 다음 스마트 생성자에 이동할 수 있습니다 : 당신은 당신이 사용하는 새로운 객체를 생성 할 때 따라서

function createMyObject3D(r, q) { 
    // some initialization logic 
    return new MyObject3D(r, q); 
} 

createMyObject3D 예를 들어 당신은 new MyObject3D을 사용하는 객체를 새로운 값으로 변경하려고합니다. 다음 방법의 장점은 다음과 같습니다.

  1. 코드가 명확하게 투명 해집니다. 따라서 그것은 동등한 추론의 대상이 될 수있다.
  2. 브랜드 개체를 반환하기 때문에 작업을 체인화 할 수 있습니다.
  3. 아무도 개체의 속성을 조작 할 수 없습니다.
  4. 함수가하는 일을 쉽게 이해할 수 있습니다.

단점은 이전 브라우저에는 없을 수도있는 Object.freeze에 달려 있다는 것입니다. 그럼에도 불구하고 물체를 얼리는 것은 선택적인 단계이며 생략 될 수 있습니다.

+1

당신은 여기에 요점이 있습니다. 그러나 나는 항상 setter 메서드를 항상 명시 적으로 사용하는 것을 싫어하지만 (맛의 문제, 실질적인 비판은 아닙니다). 내 의견으로는, 당신의 접근 방식의 주요 이점은 실제로 다르다. 최근에 defineProperty가 도입 되었기 때문에 사용자는 링크 된 속성의 암시 적 수정이 예기치 않게 발생할 수 있습니다. 그러나 메소드가 실제로 다르다는 점에서 프로그래머는 소스 코드를 훨씬 더 많이 (그리고 각 메소드별로 하나 이상의 속성을 수정한다는 것을 알 수 있습니다.) – demeshchuk

+0

@demeshchuk 더 좋은 말로 표현할 수 없었습니다. 어쨌든 내 대답을 업데이트하고 다른 대안을 제안했습니다. 하스켈처럼 새로운 대안을 선호합니다. 아직 하스켈에서 프로그램을 작성하지 않았다면해야합니다. 그것은 놀라운 언어이고, 나는 그것이 당신을 더 나은 프로그래머로 만들 것임을 보증합니다. –

+0

기능적 접근 방식은 확실히 좋습니다 (하스켈을 좋아하지만 소규모 학술 프로젝트보다 더 깊이 배울 수 있기를 바랍니다). 내 경우 벡터가 너무 자주 다시 계산되기 때문에 잔인한 행동 일지 모르지만 나는 그 결과를 비교해보고 성능을 비교해 보겠습니다. 답변 주셔서 감사합니다! – demeshchuk

관련 문제