기원
며칠 전, 나는 인기있는 미니 MVVM 프레임 워크 (avalon.js, vue.js와 같은 가벼운 프레임 워크, angularjs 및 emberjs와 같은 더 무거운 프레임 워크)의 구현을보고있었습니다. 인기있는 현대 MVVM 프레임 워크는 일반적으로 데이터 양방향 바인딩 (양방향 데이터 바인딩)을 제거하며, 이는 프레임 워크 자체의 판매 지점 (EMBER.JS는 데이터의 양방향 바인딩을 지원하지 않는 것으로 보이며 각 프레임 워크의 양방향 데이터 바인딩 구현 방법은 그다지 일관되지 않습니다. 예를 들어, Anguarjs는 내부적으로 더러운 확인을 사용하는 반면 Avalon.js의 내부 구현의 본질은 부동산 액세서를 설정하는 것입니다.
각 프레임 워크에 의해 양방향 데이터 바인딩의 구체적인 구현에 대해 논의하지는 않습니다. 우리는 프론트 엔드에서 양방향 데이터 바인딩을 구현하는 몇 가지 일반적인 방법에 대해서만 이야기하고 Avalon.js의 기술 선택에 중점을 두어 양방향 데이터 바인딩을 구현할 것입니다.
양방향 데이터 바인딩의 기존 구현
먼저 프론트 엔드 양방향 데이터 바인딩에 대해 이야기 해 봅시다. 간단히 말해서, 프레임 워크의 컨트롤러 계층 (여기서 컨트롤러 계층은 일반적인 용어이며, 이는보기 동작을 제어하고 모델 레이어를 연결하는 미들웨어로 이해할 수 있음)와 UI 디스플레이 레이어 (뷰 레이어)를 설정하여 양방향 데이터 채널을 설정합니다. 이 두 층 중 하나가 변경되면 다른 층은 자동으로 해당 변경을 즉시 수행합니다 (또는 즉시).
일반적으로,이 양방향 데이터 결합 관계 (컨트롤러 계층과 디스플레이 계층 간의 상관 프로세스)를 실현하기 위해 현재 프론트 엔드에는 세 가지 방법이 있습니다.
1. 더러운 점검
2. 관찰 메커니즘
3. 속성 액세서를 캡슐화하십시오
더러운 점검
AngularJS (여기서는 AngularJS 2.xx 버전을 나타내지 않는 Angularjs 1.xx 버전을 지칭하는 것은 양방향 데이터 바인딩의 기술적 구현이라고 말합니다. 일반적인 원칙은 AngularJS가 시퀀스를 유지 하고이 순서로 모니터링 해야하는 모든 속성을 배치한다는 것입니다. 특정 특정 이벤트가 발생하면 (이것은 시간이 지정되지 않았지만 일부 특별 이벤트에 의해 트리거됩니다) AngularJS는 $ 다이제스트 방법을 호출합니다. 이 방법의 논리는 모든 감시자를 가로 지르고 모니터링 된 속성을 비교하며 메소드 호출 전후에 속성 값이 변경되었는지 여부를 비교하는 것입니다. 변경되면 해당 핸들러가 호출됩니다. 인터넷에는이 기사와 같은 AngularJS의 양방향 데이터 바인딩의 구현 원리를 분석하는 많은 기사가 있습니다.
이 방법의 단점은 분명합니다. 트래버스 및 훈련 감시자는 특히 단일 페이지의 모니터링 수가 몇 배에 도달 할 때 매우 성능 저렴합니다.
관찰 메커니즘
블로거에는 재 인쇄 및 번역 된 기사가 있었는데, 대상 .Observe ()가 가져온 데이터 바인딩 변경은 ECMAScript7의 Object.Observe 메소드를 사용하여 객체 (또는 그 속성)를 모니터링하고 관찰하는 것을 의미합니다. 변경되면 해당 핸들러가 실행됩니다.
이것은 현재 속성 데이터 변경을 모니터링하는 가장 완벽한 방법입니다. 언어 (브라우저) 기본 지원은 이것보다 낫지 않습니다. 유일한 후회는 현재의 넓은 지원이 충분하지 않으며 완전히 홍보해야한다는 것입니다.
캡슐화 속성 액세서
PHP에는 PHP에 __get () 및 __set () 메소드와 같은 마법 방법이 있습니다. JavaScript에는 비슷한 개념이 있지만 마법 방법이 아니라 액세서라고합니다. 샘플 코드를 살펴 보겠습니다.
var data = {name : "erik", getName : function () {return this.name;}, setName : function (name) {this.name = name;}};위의 코드에서 데이터의 getName () 및 setName () 메소드와 같은 도약을 엿볼 수 있습니다. 우리는 단순히 그것을 data.name의 액세서 (또는 액세서)로 간주 할 수 있습니다.
실제로 위의 코드의 경우 더 엄격한 경우 Data.Name 속성에 직접 액세스 할 수 없습니다. Data.Name에 대한 모든 읽기 및 쓰기는 data.getName () 및 data.setName () 메소드를 통해 전달되어야합니다. 따라서 부동산이 직접 읽기 및 쓰기를 허용하지 않지만 액세서를 통해 읽고 작성해야한다고 상상해보십시오. 물론 부동산 가치 변경 모니터링과 같은 부동산의 액세서 방법을 다시 작성하여 일부 추가 기능을 수행합니다. 이것은 속성 액세서를 사용하여 양방향 데이터 바인딩을 수행하는 원칙입니다.
물론이 방법에는 단점이 있습니다. 가장 두드러진 것은 속성 모니터링이 추가 될 때마다 해당 액세서 메소드 가이 속성에 추가되어야한다는 것입니다. 그렇지 않으면이 속성의 변경이 캡처되지 않습니다.
Object.DefineProperty 메소드
국내 MVVM 프레임 워크의 원리 Avalon.js 데이터 양방향 바인딩 구현은 속성 액세서입니다. 물론 위의 예제 코드만큼 독창적이지 않습니다. ECMAScript 5.1 (ECMA-262)에 정의 된 표준 속성 개체를 사용합니다. 국내 시장 상황에 따라 일부는 물체를 지원하지 않습니다. 저수준 브라우저는 저가형 브라우저를 점차적으로 포기한 다른 MVVM 프레임 워크와 달리 완벽한 호환성을 위해 vbscript를 사용합니다.
먼저 MDN에서 Object.DefineProperty 메소드를 정의하겠습니다.
Object.DefineProperty () 메소드는 객체에서 새 특성을 직접 정의하거나 객체에서 기존 속성을 수정하고 객체를 반환합니다.
의미는 명확하고 object.defineProperty 메소드는 객체 속성을 정의하거나 기존 객체 속성을 수정하는 직접적인 방법을 제공합니다. 이 방법의 프로토 타입은 다음과 같습니다.
Object.DefineProperty (OBJ, Prop, Destcriptor)
안에,
obj, 수정 될 물체
속성 이름이 수정 된 소품
설명자, 수정할 속성의 관련 설명
설명자는 객체를 전달해야하며 기본값은 다음과 같습니다.
/*** @{param} descriptor*/{configurable : false, enumerable : false, stable : false, value : null, set : undrefined, get : undefined}속성이 구성 가능한지 구성 가능합니다. 구성 가능한 의미는 다음이 포함됩니다. 속성을 삭제할 수 있는지 여부, 쓰기 가능, 열거 가능 및 속성의 구성 가능한 속성을 수정할 수 있는지 여부.
속성이 열거 될 수 있는지 여부에 관계없이 열거 할 수 있습니다. 열거 가능한 의미에는 다음이 포함됩니다.
속성을 다시 작성할 수 있는지 여부를 쓸 수 있습니다. 재 작성 가능의 의미에는 다음이 포함됩니다. 속성을 재 할 수 있는지 여부.
값, 속성의 기본값입니다.
속성 재 작성자 세트 (지금은 그렇습니다). 속성이 재 할당되면이 메소드는 자동으로 호출됩니다.
재산의 독자 (지금은 그게 다야)를 얻으십시오. 속성에 액세스하고 읽히면이 방법은 자동으로 호출됩니다.
다음은 샘플 코드입니다.
var o = {}; object.DefineProperty (o, 'name', {value : 'erik'}); console.log (Object.getOwnPropertyDescriptor (o, 'name')); // object {value : "erik", writable : false, hanumerable : false, configurable : false} object.defineProperty (o, 'ague', {value : 26, configurable : true, writable : true}); console.log (o.age); // 26o.age = 18; console.log (O.age); // 18. 연령 속성은 다시 쓰기 쉬운 콘솔이기 때문에 (Object.Keys (o)); // []. 이름이나 나이 속성은 열거 가능한 대상이 아닙니다 .DefineProperty (o, 'sex', {value : 'male', writable : false}); o.sex = '여성'; // 여기의 할당은 실제로 비효율적 인 console.log (o.sex)입니다. // 'male'; o.sex 삭제; // false, 속성 삭제 조치도 유효하지 않습니다위의 예제 이후, 정상적인 상황에서 Object.DefinePropert ()의 사용은 비교적 간단합니다.
그러나 여전히 추가주의를 기울여야하는 것이 여전히 있습니다. Object.DefineProperty () 메소드가 속성을 설정할 때 속성은 액세서리 속성 (세트 및 get)과 동시에 쓰기 가능 또는 값 속성을 선언 할 수 없습니다. 이는 특정 속성이 쓰기 가능 또는 값 속성으로 설정된 경우이 속성은 GET 및 SET을 선언 할 수 없으며 그 반대도 마찬가지입니다.
Object.DefineProperty ()가 속성을 선언 할 때 동일한 속성에 대해 두 가지 이상의 액세스 컨트롤이 허용되지 않기 때문입니다.
샘플 코드,
var o = {}, myName = 'erik'; object.defineProperty (o, 'name', {value : myName, set : function (name) {myName = name;}, get : function () {return myName;}});위의 코드는 괜찮은 것처럼 보이지만 실제로 실행되면 오류가보고되며 오류는 다음과 같이보고됩니다.
TypeError : 유효하지 않은 속성. 부동산은 액세서리를 가질 수없고 쓸 수 없거나 가치가 있습니다.
여기서 이름 속성은 값 속성을 선언하기 때문에 세트 및 속성을 동시에 가져옵니다. 둘 다 이름 속성에 대한 두 개의 읽기 및 쓰기 컨트롤을 제공합니다. 값 기능이 여기에서 선언되지 않았지만 쓰기 가능한 기능이 선언되면 결과는 동일하고 오류가보고됩니다.