최근에는 Angular 개발자가 인덱싱된 DB와 같은 WEB 표준을 사용하여 클라우드 데이터, 특히 Azure 모바일 서비스를 사용할 수 있도록 돕기 위해 Angular Cloud Data Connector 프로젝트를 개발했습니다. 저는 JavaScript 개발자가 전용 멤버를 개체에 포함시킬 수 있는 방법을 만들려고 합니다.
이 문제를 해결하기 위한 나의 기술은 제가 클로저 공간이라고 명명한 것을 사용합니다. 이 소개 글에서는 프로젝트에서 이를 사용하는 방법과 이것이 주요 브라우저의 성능 및 메모리에 미치는 영향을 공유하고 싶습니다.
깊이 공부하기 전에 먼저 private 멤버를 사용해야 하는 이유와 private 멤버를 시뮬레이션하는 다른 방법에 대해 알아보겠습니다.
이 기사에 대해 댓글을 달고 싶다면 @deltakosh로 트윗해 주세요.
JavaScript에서 객체를 생성할 때 값 멤버를 선언할 수 있습니다. 이에 대한 읽기/쓰기 액세스를 제어하려는 경우 다음과 같이 선언할 수 있습니다.
var entity = {}; entity._property = "hello world"; Object.defineProperty(entity, "property", { get: function () { return this._property; }, set: function (value) { this._property = value; }, enumerable: true, configurable: true });
이러한 방식으로 읽기 및 쓰기 작업을 완전히 제어할 수 있습니다. 문제는 _property 멤버가 여전히 직접 액세스되고 수정될 수 있다는 것입니다.
이것이 객체 메서드를 통해 액세스할 수 있는 private 멤버를 선언하는 보다 안정적이고 신뢰할 수 있는 방법이 필요한 이유입니다.
해결책은 폐쇄공간을 활용하는 것이다. 내부 함수가 외부 함수 범위의 변수에 액세스할 때마다 브라우저는 메모리 공간을 할당합니다. 때로는 까다롭지만 우리 문제에서는 이것이 완벽한 해결책입니다.
我们在上个代码版本中添加这个特性: var createProperty = function (obj, prop, currentValue) { Object.defineProperty(obj, prop, { get: function () { return currentValue; }, set: function (value) { currentValue = value; }, enumerable: true, configurable: true }); } var entity = {}; var myVar = "hello world";createProperty(entity, "property", myVar);
예제에서 createProperty 함수에는 currentValue 변수가 있고 get 및 set 메소드가 있습니다. 이 변수는 get 및 set 함수의 클로저 공간에 저장됩니다. 이제 이 두 함수만 currentValue 변수를 보고 업데이트할 수 있습니다!
유일한 경고, 주의 사항은 소스 값(myVar)에 계속 액세스할 수 있다는 것입니다. 또 다른 더 강력한 버전(myVar 변수 보호)은 다음과 같습니다.
var createProperty = function (obj, prop) { var currentValue = obj[prop]; Object.defineProperty(obj, prop, { get: function () { return currentValue; }, set: function (value) { currentValue = value; }, enumerable: true, configurable: true }); } var entity = { property: "hello world" }; createProperty(entity, "property");
이 함수를 사용하면 소스 값도 삭제됩니다(삭제됨, 참고: 직접 할당할 수 없음을 의미). 끝났습니다!
이제 성능을 살펴보겠습니다.
분명히 단순 변수, 클로저 공간 또는 심지어 (객체) 속성에 비해 훨씬 느리고 리소스 집약적입니다. 이것이 바로 이 기사가 일반적인 방법과 폐쇄 공간 메커니즘 간의 차이점에 더 중점을 두는 이유입니다.
폐쇄 공간 메커니즘이 표준 방법보다 더 많은 리소스를 소비하지 않는다는 것을 증명하기 위해 벤치마크로 다음 코드를 작성했습니다.
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> </head> <style> html { font-family: "Helvetica Neue", Helvetica; } </style> <body> <p id="results">Computing...</p> <script> var results = document.getElementById("results"); var sampleSize = 1000000; var opCounts = 1000000; var entities = []; setTimeout(function () { // Creating entities for (var index = 0; index < sampleSize; index++) { entities.push({ property: "hello world (" + index + ")" }); } // Random reads var start = new Date().getTime(); for (index = 0; index < opCounts; index++) { var position = Math.floor(Math.random() * entities.length); var temp = entities[position].property; } var end = new Date().getTime(); results.innerHTML = "<strong>Results:</strong><br>Using member access: <strong>" + (end - start) + "</strong> ms"; }, 0); setTimeout(function () { // Closure space ======================================= var createProperty = function (obj, prop, currentValue) { Object.defineProperty(obj, prop, { get: function () { return currentValue; }, set: function (value) { currentValue = value; }, enumerable: true, configurable: true }); } // Adding property and using closure space to save private value for (var index = 0; index < sampleSize; index++) { var entity = entities[index]; var currentValue = entity.property; createProperty(entity, "property", currentValue); } // Random reads var start = new Date().getTime(); for (index = 0; index < opCounts; index++) { var position = Math.floor(Math.random() * entities.length); var temp = entities[position].property; } var end = new Date().getTime(); results.innerHTML += "<br>Using closure space: <strong>" + (end - start) + "</strong> ms"; }, 0); setTimeout(function () { // Using local member ======================================= // Adding property and using local member to save private value for (var index = 0; index < sampleSize; index++) { var entity = entities[index]; entity._property = entity.property; Object.defineProperty(entity, "property", { get: function () { return this._property; }, set: function (value) { this._property = value; }, enumerable: true, configurable: true }); } // Random reads var start = new Date().getTime(); for (index = 0; index < opCounts; index++) { var position = Math.floor(Math.random() * entities.length); var temp = entities[position].property; } var end = new Date().getTime(); results.innerHTML += "<br>Using local member: <strong>" + (end - start) + "</strong> ms"; }, 0); </script> </body> </html>
모두 속성 멤버를 사용하여 백만 개의 개체를 만들었습니다. 다음 세 가지 테스트를 완료하려면
속성에 대해 1백만 번의 무작위 액세스를 수행합니다.
100만 개의 무작위 접근 폐쇄 공간 구현 버전을 수행합니다.
일반 get/set 구현에 대해 100만 번의 무작위 액세스를 수행합니다.
테스트 결과는 다음 표와 차트에 나와 있습니다.
폐쇄 공간 구현은 다음과 같습니다. 브라우저에 따라 기존 구현보다 항상 더 빠르게 성능을 최적화할 수도 있습니다.
Chrome의 성능이 예상보다 낮습니다. 버그가 있을 수 있으니 확인을 위해 구글 프로젝트팀에 연락해서 발생한 증상을 설명드렸습니다. 또한 Windows 10에 기본적으로 설치되는 Microsoft의 새로 출시된 브라우저인 Microsoft Edge의 성능을 테스트하려면 클릭하여 다운로드할 수 있습니다.
그러나 주의 깊게 연구하면 클로저 공간이나 속성을 사용하는 것이 변수 멤버에 직접 액세스하는 것보다 약 10배 빠르다는 것을 알 수 있습니다. 그러므로 적절하고 주의해서 사용하십시오.
또한 이 기술이 메모리를 너무 많이 소모하지 않는지 확인해야 합니다. 메모리 사용량 벤치마크를 테스트하기 위해 다음 코드 조각을 작성했습니다.
var sampleSize = 1000000; var entities = []; // Creating entities for (var index = 0; index < sampleSize; index++) { entities.push({ property: "hello world (" + index + ")" });}
var sampleSize = 1000000; var entities = []; // Adding property and using local member to save private value for (var index = 0; index < sampleSize; index++) { var entity = {}; entity._property = "hello world (" + index + ")"; Object.defineProperty(entity, "property", { get: function () { return this._property; }, set: function (value) { this._property = value; }, enumerable: true, configurable: true }); entities.push(entity); }
var sampleSize = 1000000; var entities = []; var createProperty = function (obj, prop, currentValue) { Object.defineProperty(obj, prop, { get: function () { return currentValue; }, set: function (value) { currentValue = value; }, enumerable: true, configurable: true }); } // Adding property and using closure space to save private value for (var index = 0; index < sampleSize; index++) { var entity = {}; var currentValue = "hello world (" + index + ")"; createProperty(entity, "property", currentValue); entities.push(entity); }
그 후 세 가지 주요 브라우저에서 세 가지 코드를 모두 실행하고 (브라우저) 내장 메모리 프로파일러를 실행했습니다(이 예에서는 F12 도구 모음이 사용됨). :
내 컴퓨터에서 실행한 결과는 다음과 같습니다.
클로저 공간과 기존 방법에 대해서는 Chrome에서만 클로저 공간(메모리 사용량)이 약간 더 나은 성능을 발휘하지만 IE11과 Firefox에서는 메모리 사용량이 증가하지만 브라우저의 비교 결과는 최신 브라우저의 경우 e-사용자가 가장 많습니다. 아마도 당신은 차이점을 느끼지 못할 것입니다.
Microsoft가 오픈 소스 Javascript 주제에 대한 일련의 무료 학습 자료를 제공하고 더 많은 Microsoft Edge Coming 시리즈를 만들기 위한 임무를 시작하고 있다는 사실에 놀라실 수도 있습니다. . 내 기사를 확인하세요:
HTML5 및 Babylon.JS 기반 WebGL 3D 기본 개발
ASP 기반 단일 페이지 애플리케이션 구축. NET 및 AngularJS
HTML 고급 이미지 기술
또는 우리 팀 시리즈:
HTML/ JavaScript 성능 최적화 사용 팁(이 시리즈는 반응형 디자인부터 캐주얼 게임의 성능 최적화까지 7개 부분으로 구성됨)
최신 웹 플랫폼(HTML, CSS 및 JS 기본)으로 빠르게 시작하세요.
HTML 및 JavaScript를 사용하여 빠르게 시작하기 위한 범용 Windows 앱 개발(자체 JS로 앱 구축)
및 일부 무료 도구: 시각적 Mac, Linux 또는 Windows용 Studio 커뮤니티, Azure 평가판 및 브라우저 간 테스트 도구입니다.
보시다시피 폐쇄 공간 속성(메커니즘)은 진정한 개인 데이터를 생성하는 좋은 방법입니다. 약간의 메모리 소모 증가(문제)를 겪어야 할 수도 있지만, 제 생각에는 매우 합리적이라고 생각합니다(이 가격을 기존 방식에 비해 더 높은 성능 향상으로 바꿀 수 있습니다).
참고로, 직접 해보고 싶다면 여기에서 코드를 다운로드할 수 있습니다. 여기에서 Azure 모바일 서비스에 대한 좋은 기사 "방법"을 추천하세요.
위 내용은 JavaScript 개체에 비공개 멤버를 포함하는 방법에 대한 예제 코드(그림)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!