> 웹 프론트엔드 > JS 튜토리얼 > JavaScript 개체에 비공개 멤버를 포함하는 방법에 대한 예제 코드(그림)

JavaScript 개체에 비공개 멤버를 포함하는 방법에 대한 예제 코드(그림)

黄舟
풀어 주다: 2017-03-11 15:27:53
원래의
1517명이 탐색했습니다.

최근에는 Angular 개발자가 인덱싱된 DB와 같은 WEB 표준을 사용하여 클라우드 데이터, 특히 Azure 모바일 서비스를 사용할 수 있도록 돕기 위해 Angular Cloud Data Connector 프로젝트를 개발했습니다. 저는 JavaScript 개발자가 전용 멤버를 개체에 포함시킬 수 있는 방법을 만들려고 합니다.

이 문제를 해결하기 위한 나의 기술은 제가 클로저 공간이라고 명명한 것을 사용합니다. 이 소개 글에서는 프로젝트에서 이를 사용하는 방법과 이것이 주요 브라우저의 성능 및 메모리에 미치는 영향을 공유하고 싶습니다.

깊이 공부하기 전에 먼저 private 멤버를 사용해야 하는 이유와 private 멤버를 시뮬레이션하는 다른 방법에 대해 알아보겠습니다.

이 기사에 대해 댓글을 달고 싶다면 @deltakosh로 트윗해 주세요.

1. Private Members를 사용하는 이유

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 멤버를 선언하는 보다 안정적이고 신뢰할 수 있는 방법이 필요한 이유입니다.

2. 폐쇄공간(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    });
                    } 
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");
로그인 후 복사

이 함수를 사용하면 소스 값도 삭제됩니다(삭제됨, 참고: 직접 할당할 수 없음을 의미). 끝났습니다!

3. 성능 고려 사항

이제 성능을 살펴보겠습니다.

분명히 단순 변수, 클로저 공간 또는 심지어 (객체) 속성에 비해 훨씬 느리고 리소스 집약적입니다. 이것이 바로 이 기사가 일반적인 방법과 폐쇄 공간 메커니즘 간의 차이점에 더 중점을 두는 이유입니다.

폐쇄 공간 메커니즘이 표준 방법보다 더 많은 리소스를 소비하지 않는다는 것을 증명하기 위해 벤치마크로 다음 코드를 작성했습니다.

<!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만 번의 무작위 액세스를 수행합니다.

테스트 결과는 다음 표와 차트에 나와 있습니다.

JavaScript 개체에 비공개 멤버를 포함하는 방법에 대한 예제 코드(그림)JavaScript 개체에 비공개 멤버를 포함하는 방법에 대한 예제 코드(그림)

폐쇄 공간 구현은 다음과 같습니다. 브라우저에 따라 기존 구현보다 항상 더 빠르게 성능을 최적화할 수도 있습니다.

Chrome의 성능이 예상보다 낮습니다. 버그가 있을 수 있으니 확인을 위해 구글 프로젝트팀에 연락해서 발생한 증상을 설명드렸습니다. 또한 Windows 10에 기본적으로 설치되는 Microsoft의 새로 출시된 브라우저인 Microsoft Edge의 성능을 테스트하려면 클릭하여 다운로드할 수 있습니다.

그러나 주의 깊게 연구하면 클로저 공간이나 속성을 사용하는 것이 변수 멤버에 직접 액세스하는 것보다 약 10배 빠르다는 것을 알 수 있습니다. 그러므로 적절하고 주의해서 사용하십시오.

JavaScript 개체에 비공개 멤버를 포함하는 방법에 대한 예제 코드(그림)

4. 메모리 공간

또한 이 기술이 메모리를 너무 많이 소모하지 않는지 확인해야 합니다. 메모리 사용량 벤치마크를 테스트하기 위해 다음 코드 조각을 작성했습니다.

직접 속성 참조 버전(참조 코드)

var sampleSize = 1000000;
 var entities = []; 
// Creating entities
for (var index = 0; index < sampleSize; index++) {
    entities.push({
            property: "hello world (" + index + ")"
});}
로그인 후 복사

Regular Way 버전(Regular Way, get/set)

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);
}
로그인 후 복사

Closure Space 버전

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 도구 모음이 사용됨). :

JavaScript 개체에 비공개 멤버를 포함하는 방법에 대한 예제 코드(그림)

내 컴퓨터에서 실행한 결과는 다음과 같습니다.

JavaScript 개체에 비공개 멤버를 포함하는 방법에 대한 예제 코드(그림)

클로저 공간과 기존 방법에 대해서는 Chrome에서만 클로저 공간(메모리 사용량)이 약간 더 나은 성능을 발휘하지만 IE11과 Firefox에서는 메모리 사용량이 증가하지만 브라우저의 비교 결과는 최신 브라우저의 경우 e-사용자가 가장 많습니다. 아마도 당신은 차이점을 느끼지 못할 것입니다.

추가 JavaScript 실습

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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿