Private 멤버의 문법적 특징을 구현하는 방법과 JavaScript_javascript 기술을 기반으로 Private 멤버를 구현하는 방법
머리말
객체 지향 프로그래밍 패러다임에서 캡슐화는 필수 개념이며 Java, C와 같은 전통적인 객체 지향 언어에서는 프라이빗 멤버가 캡슐화를 달성하는 중요한 방법입니다. 그러나 JavaScript에서는 실제로 문법적 기능 측면에서 프라이빗 멤버를 지원하지 않으므로 개발자는 JS에서 프라이빗 멤버를 구현하기 위해 다양한 트릭을 사용하게 됩니다. 다음은 JS에서 프라이빗 멤버 기능의 현재 구현을 소개합니다. 그들의 장점과 단점의 비교.
일부 기존 구현 솔루션
일반적인 명명 방식
밑줄 '_'로 시작하는 멤버 이름은 프라이빗 멤버로 간주되어 클래스 멤버 메서드만 접근 및 호출이 허용되며, 프라이빗 멤버는 외부에서 접근이 허용되지 않는다는 점에 동의합니다. 간단한 코드는 다음과 같습니다.
자바스크립트
var MyClass = function () { this._privateProp = ‘privateProp'; }; MyClass.prototype.getPrivateProp = function () { return this._privateProp; }; var my = new MyClass(); alert(my.getPrivateProp()); // ‘privateProp'; alert(my._privateProp); // 并未真正隐藏,依然弹出 ‘privateProp'
장점
명명 규칙이 코드 수준 작업 없이 전용 멤버를 구현하는 가장 간단한 솔루션이라는 것은 의심의 여지가 없습니다.
디버깅이 편리하며, 콘솔에서 개체의 프라이빗 멤버를 직접 볼 수 있어 문제 해결이 쉽습니다.
ie6에서 지원되는 우수한 호환성
부족합니다
비공개 멤버에 대한 외부 접근 및 변경을 막을 수 있는 방법은 없습니다. 약관을 모르거나 준수하지 않는 개발자가 비공개 속성을 변경하는 경우에는 어떻게 할 수 없습니다.
물론 모든 사람이 이 합의를 따르도록 강요하거나 설득해야 합니다. 물론 이는 코드 표준이 있는 팀에서는 큰 문제가 아닙니다.
es6 심볼 솔루션
es6에서는 private 멤버를 구현하기 위해 도입된 Symbol 기능이 도입되었습니다.
주요 아이디어는 각 비공개 멤버의 이름에 대해 임의의 고유한 문자열 키를 생성하는 것입니다. 이 키는 외부 세계에는 보이지 않습니다. 샘플 코드는 다음과 같습니다.
자바스크립트
(function() { var privateProp = Symbol(); // 每次调用会产生一个唯一的key function MyClass() { this[privateProp] = ‘privateProp'; // 闭包内引用到这个 key } MyClass.prototype.getPrivateProp = function () { return this[privateProp]; }; })(); var my = new MyClass(); alert(my.getPrivateProp()); // ‘privateProp'; alert(my.privateProp); // 弹出 undefined,因为成员的key其实是随机字符串
장점
네이밍 규칙 체계의 단점을 보완하며 외부 당사자는 일반 채널을 통해 비공개 멤버에 액세스할 수 없습니다.
디버깅의 편리성은 일반적으로 기호 생성자에 문자열 매개변수가 전달되고 콘솔에 해당 개인 속성 이름이 다음과 같이 표시됩니다. Symbol(key)
부족합니다
글이 좀 어색하네요. 내부 메소드에서 접근할 수 있도록 private 멤버별로 클로저 변수를 생성해야 합니다.
외부적으로는 여전히 Object.getOwnPropertySymbols를 통해 인스턴스의 기호 속성 이름을 얻을 수 있으며 이 이름을 통해 전용 멤버에 대한 액세스 권한을 얻을 수 있습니다. 이 시나리오는 상대적으로 드물게 발생하며, 이 접근 방식을 아는 개발자 수준은 자신의 행동이 미치는 영향을 충분히 알 수 있다고 믿기 때문에 이러한 단점은 실제 단점이 아닙니다.
es6 WeakMap 솔루션
Map 및 WeakMap 컨테이너는 es6에서 도입되었습니다. 가장 큰 특징은 컨테이너의 키 이름이 어떤 데이터 유형이든 가능하다는 것입니다. 원래 의도는 private 멤버 도입을 구현하는 것이 아니었지만 예기치 않게 구현하는 데 사용될 수 있습니다. 비공개 회원 기능.주요 아이디어는 클래스 수준에서 WeakMap 컨테이너를 만들어 각 인스턴스의 전용 멤버를 저장하는 것입니다. 이 컨테이너는 외부에는 보이지 않으며 내부 메서드를 통해 인스턴스를 키 이름으로 얻습니다. . 컨테이너의 해당 인스턴스의 Private 멤버는 다음과 같습니다.
자바스크립트
(function() { var privateStore = new WeakMap(); // 私有成员存储容器 function MyClass() { privateStore.set(this, {privateProp: ‘privateProp'}); // 闭包内引用到privateStore, 用当前实例做 key,设置私有成员 } MyClass.prototype.getPrivateProp = function () { return privateStore.get(this).privateProp; }; })(); var my = new MyClass(); alert(my.getPrivateProp()); // ‘privateProp'; alert(my.privateProp); // 弹出 undefined,实例上并没有 privateProp 属性
优点
弥补了命名约定方案的缺陷,外部无法通过正常途径获得私有成员的访问权。
对 WeakMap 做一些封装,抽出一个私有特性的实现模块,可以在写法上相对 Symbol 方案更加简洁干净,其中一种封装的实现可以查看参考文章3。
最后一个是个人认为最大的优势:基于 WeakMap 方案,可以方便的实现保护成员特性(这个话题会在其他文章说到:))
不足
不好调试,因为是私有成员都在闭包容器内,无法在控制台打印实例查看对应的私有成员
待确认的性能问题,根据 es6的相关邮件列表,weakmap 内部似乎是通过顺序一一对比的方式去定位 key 的,时间复杂度为 O(n),和 hash 算法的 O(1)相比会慢不少
最大的缺陷则是兼容性带来的内存膨胀问题,在不支持 WeakMap 的浏览器中是无法实现 WeakMap 的弱引用特性,因此实例无法被垃圾回收。 比如示例代码中 privateProp 是一个很大的数据项,无弱引用的情况下,实例无法回收,从而造成内存泄露。
现有实现方案小结
从上面的对比来看,Symbol方案最大优势在于很容易模拟实现;而WeakMap的优势则是能够实现保护成员, 现阶段无法忍受的不足是无法模拟实现弱引用特性而导致的内存问题。于是我的思路又转向了将两者优势结合起来的方向。
Symbol + 类WeakMap 的整合方案
在 WeakMap 的方案中最大的问题是无法 shim 弱引用,较次要的问题是不大方便调试。
shim 出来的 WeakMap 主要是无法追溯实例的生命周期,而实例上的私有成员的生命周期又是依赖实例, 因此将实例级别的私有成员部分放在实例上不就好了? 实例没了,自然其属性也随之摧毁。而私有存储区域的隐藏则可以使用 Symol 来做。
该方案的提供一个 createPrivate 函数,该函数会返回一个私有的 token 函数,对外不可见,对内通过闭包函数获得, 传入当前实例会返回当前实例的私有存储区域。使用方式如下:
JavaScript
(function() { var $private = createPrivate(); // 私有成员 token 函数,可以传入对象参数,会作为原型链上的私有成员 function MyClass() { $private(this).privateProp = ‘privateProp' ; // 闭包内引用到privateStore, 用当前实例做 key,设置私有成员 } MyClass.prototype.getPrivateProp = function () { return $private(this).privateProp; }; })(); var my = new MyClass(); alert(my.getPrivateProp()); // ‘privateProp'; alert(my.privateProp); // 弹出 undefined,实例上并没有 privateProp 属性
代码中主要就是实现 createPrivate 函数,大概的实现如下:
JavaScript
// createPrivate.js function createPrivate(prototype) { var privateStore = Symbol('privateStore'); var classToken = Symbol(‘classToken'); return function getPrivate(instance) { if (!instance.hasOwnProperty(privateStore)) { instance[privateStore] = {}; } var store = instance[classToken]; store[token] = store[token] || Object.create(prototype || {}); return store[token]; }; }
上述实现做了两层存储,privateStore 这层是实例上统一的私有成员存储区域,而 classToken 对应的则是继承层次之间不同类的私有成员定义,基类有基类的私有成员区域,子类和基类的私有成员区域是不同的。
当然,只做一层的存储也可以实现,两层存储仅仅是为了调试方便,可以直接在控制台通过Symbol(‘privateStore')这个属性来查看实例各个层次的私有部分。
奇葩的 es5 property getter 拦截方案
该方案纯粹是闲得无聊玩了玩,主要是利用了 es5 提供的 getter,根据 argument.callee.caller 去判断调用场景,如果是外部的则抛异常或返回 undefined, 如果是内部调用则返回真正的私有成员,实现起来比较复杂,且不支持 strict 模式,不推荐使用。 有兴趣的同学可以看看实现。
总结
以上几个方案对比下来,我个人是倾向 Symbol+WeakMap 的整合方案,结合了两者的优点,又弥补了 WeakMap 的不足和 Symbol 书写的冗余。 当然了,我相信随着 JS 的发展,私有成员和保护成员也迟早会在语法层面上进行支持,正如 es6 对 class 关键字和 super 语法糖的支持一样, 只是现阶段需要开发者使用一些技巧去填补语言特性上的空白。
Javascript私有成员的实现方式
总体来讲这本书还是可以的,但看完这本书还留了几个问题一直困扰着我,如js中私有变量的实现,prototype等,经过自己一系列测试,现在终于弄明白了。
很多书上都是说,Javascript是不能真正实现Javascript私有成员的,因此在开发的时候,统一约定 __ 两个下划线开头为私有变量。
后来,发现Javascript中闭包的特性,从而彻底解决了Javascript私有成员的问题。
function testFn(){ var _Name;//定义Javascript私有成员 this.setName = function(name){ _Name = name; //从当前执行环境中获取_Name } this.getName = function(){ return _Name; } }// End testFn var test = testFn(); alert(typeof test._Name === "undefined")//true test.setName("KenChen");
test._Name 根本访问不到,但是用对象方法能访问到,因为闭包能从当前的执行环境中获取信息。
接下来我们看看,共有成员是怎样实现的
function testFn(name){ this.Name = name; this.getName = function(){ return this.Name; } } var test = new testFn("KenChen"); test.getName(); //KenChen test.Name = "CC"; est.getName();//CC
接下来在看看类静态变量是怎样实现的
function testFn(){ } testFn.Name = "KenChen"; alert(testFn.Name);//KenChen testFn.Name = "CC"; alert(testFn.Name);//CC

웹 개발에서 JavaScript의 주요 용도에는 클라이언트 상호 작용, 양식 검증 및 비동기 통신이 포함됩니다. 1) DOM 운영을 통한 동적 컨텐츠 업데이트 및 사용자 상호 작용; 2) 사용자가 사용자 경험을 향상시키기 위해 데이터를 제출하기 전에 클라이언트 확인이 수행됩니다. 3) 서버와의 진실한 통신은 Ajax 기술을 통해 달성됩니다.

보다 효율적인 코드를 작성하고 성능 병목 현상 및 최적화 전략을 이해하는 데 도움이되기 때문에 JavaScript 엔진이 내부적으로 작동하는 방식을 이해하는 것은 개발자에게 중요합니다. 1) 엔진의 워크 플로에는 구문 분석, 컴파일 및 실행; 2) 실행 프로세스 중에 엔진은 인라인 캐시 및 숨겨진 클래스와 같은 동적 최적화를 수행합니다. 3) 모범 사례에는 글로벌 변수를 피하고 루프 최적화, Const 및 Lets 사용 및 과도한 폐쇄 사용을 피하는 것이 포함됩니다.

Python은 부드러운 학습 곡선과 간결한 구문으로 초보자에게 더 적합합니다. JavaScript는 가파른 학습 곡선과 유연한 구문으로 프론트 엔드 개발에 적합합니다. 1. Python Syntax는 직관적이며 데이터 과학 및 백엔드 개발에 적합합니다. 2. JavaScript는 유연하며 프론트 엔드 및 서버 측 프로그래밍에서 널리 사용됩니다.

Python과 JavaScript는 커뮤니티, 라이브러리 및 리소스 측면에서 고유 한 장점과 단점이 있습니다. 1) Python 커뮤니티는 친절하고 초보자에게 적합하지만 프론트 엔드 개발 리소스는 JavaScript만큼 풍부하지 않습니다. 2) Python은 데이터 과학 및 기계 학습 라이브러리에서 강력하며 JavaScript는 프론트 엔드 개발 라이브러리 및 프레임 워크에서 더 좋습니다. 3) 둘 다 풍부한 학습 리소스를 가지고 있지만 Python은 공식 문서로 시작하는 데 적합하지만 JavaScript는 MDNWebDocs에서 더 좋습니다. 선택은 프로젝트 요구와 개인적인 이익을 기반으로해야합니다.

C/C에서 JavaScript로 전환하려면 동적 타이핑, 쓰레기 수집 및 비동기 프로그래밍으로 적응해야합니다. 1) C/C는 수동 메모리 관리가 필요한 정적으로 입력 한 언어이며 JavaScript는 동적으로 입력하고 쓰레기 수집이 자동으로 처리됩니다. 2) C/C를 기계 코드로 컴파일 해야하는 반면 JavaScript는 해석 된 언어입니다. 3) JavaScript는 폐쇄, 프로토 타입 체인 및 약속과 같은 개념을 소개하여 유연성과 비동기 프로그래밍 기능을 향상시킵니다.

각각의 엔진의 구현 원리 및 최적화 전략이 다르기 때문에 JavaScript 엔진은 JavaScript 코드를 구문 분석하고 실행할 때 다른 영향을 미칩니다. 1. 어휘 분석 : 소스 코드를 어휘 단위로 변환합니다. 2. 문법 분석 : 추상 구문 트리를 생성합니다. 3. 최적화 및 컴파일 : JIT 컴파일러를 통해 기계 코드를 생성합니다. 4. 실행 : 기계 코드를 실행하십시오. V8 엔진은 즉각적인 컴파일 및 숨겨진 클래스를 통해 최적화하여 Spidermonkey는 유형 추론 시스템을 사용하여 동일한 코드에서 성능이 다른 성능을 제공합니다.

실제 세계에서 JavaScript의 응용 프로그램에는 서버 측 프로그래밍, 모바일 애플리케이션 개발 및 사물 인터넷 제어가 포함됩니다. 1. 서버 측 프로그래밍은 Node.js를 통해 실현되며 동시 요청 처리에 적합합니다. 2. 모바일 애플리케이션 개발은 재교육을 통해 수행되며 크로스 플랫폼 배포를 지원합니다. 3. Johnny-Five 라이브러리를 통한 IoT 장치 제어에 사용되며 하드웨어 상호 작용에 적합합니다.

일상적인 기술 도구를 사용하여 기능적 다중 테넌트 SaaS 응용 프로그램 (Edtech 앱)을 구축했으며 동일한 작업을 수행 할 수 있습니다. 먼저, 다중 테넌트 SaaS 응용 프로그램은 무엇입니까? 멀티 테넌트 SAAS 응용 프로그램은 노래에서 여러 고객에게 서비스를 제공 할 수 있습니다.


핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

SublimeText3 Linux 새 버전
SublimeText3 Linux 최신 버전

에디트플러스 중국어 크랙 버전
작은 크기, 구문 강조, 코드 프롬프트 기능을 지원하지 않음

PhpStorm 맥 버전
최신(2018.2.1) 전문 PHP 통합 개발 도구

MinGW - Windows용 미니멀리스트 GNU
이 프로젝트는 osdn.net/projects/mingw로 마이그레이션되는 중입니다. 계속해서 그곳에서 우리를 팔로우할 수 있습니다. MinGW: GCC(GNU Compiler Collection)의 기본 Windows 포트로, 기본 Windows 애플리케이션을 구축하기 위한 무료 배포 가능 가져오기 라이브러리 및 헤더 파일로 C99 기능을 지원하는 MSVC 런타임에 대한 확장이 포함되어 있습니다. 모든 MinGW 소프트웨어는 64비트 Windows 플랫폼에서 실행될 수 있습니다.

ZendStudio 13.5.1 맥
강력한 PHP 통합 개발 환경
