기본 캡슐화 방법
다음 예를 참조하세요.
var Person = function(name,age){ this.name = name; this.age = age || "未填写"; this.hobbys = []; } Person.prototype = { sayName:function(){ console.log(this.name); }, sayAge:function(){ console.log(this.age); }, addHobby:function(hobbys){ this.hobbys = this.hobbys.concat(hobbys); } } var person1 = new Person("Jane","20"); var person2 = new Person("TabWeng","21"); person1.addHobby(['sing','drawing']); person2.addHobby(['football','study','running']); person1.sayName(); console.log(person1.hobbys.toString()); person2.sayName(); console.log(person2.hobbys.toString());
실행 결과:
Jane
노래, 그림
TabWeng
축구, 공부, 달리기
이것은 JavaScript 개체 생성에서 언급됩니다. 프로토타입에 공유할 수 있는 속성과 메서드를 작성합니다. 각 인스턴스에 고유한 복사본이 있어야 하는 속성과 메서드가 배치됩니다. 생성자에 있습니다.
입력 이름에 숫자를 포함할 수 없는 문제가 있습니다. 어떻게 해결하나요? 해결책은 이름을 확인하는 함수를 작성하고 이 함수를 프로토타입에 작성하는 것입니다.
var Person = function(name,age){ //校验名称 if(this.checkName(name)){ throw new Error("名字 "+name+" 不能存在数字"); } this.name = name; this.age = age || "未填写"; this.hobbys = []; } Person.prototype = { //校验函数 checkName:function(name){ re = /\d/; return re.test(name); }, sayName:function(){ console.log(this.name); }, sayAge:function(){ console.log(this.age); }, addHobby:function(hobbys){ this.hobbys = this.hobbys.concat(hobbys); } } var person1 = new Person("Helen666","20"); var person2 = new Person("TabWeng","21"); person1.addHobby(['sing','drawing']); person2.addHobby(['football','study','running']); person1.sayName(); console.log(person1.hobbys.toString()); person2.sayName(); console.log(person2.hobbys.toString());
이 코드에서는 이름을 확인하기 위해 checkName() 함수를 작성했습니다. 당분간은 숫자가 없는지 확인하고 첫 번째 줄에서 확인을 수행합니다. 확인에 실패하면 예외가 발생합니다.
여기서 Helen666이라는 이름을 전달했는데 다음 예외가 발생했습니다.
오류: Helen666이라는 이름에는 숫자를 포함할 수 없습니다.
이런 방식으로 기본 캡슐화가 달성됩니다. , 내부 구현 확인.
그러나 또 다른 문제가 있습니다.
var person1 = new Person("Helen","20"); person1.name = "Helen666"; person1.sayName(); //Helen666
이렇게 하면 이름이 여전히 불법적인 이름으로 수정될 수 있으므로 다음을 사용하는 것을 고려했습니다. get 메소드와 set 메소드는 set 메소드를 통해서만 값을 할당하고, set 메소드를 통해서 검증하고, get 메소드를 통해서만 값을 얻을 수 있습니다. 현재 수정된 코드는 다음과 같습니다.
// Interfacevar People = new Interface("People",["setName","getName","setAge","getAge","addHobby","getHobby","sayName","sayAge"]);var Person = function(name,age){ //implement People this.setName(name); this.setAge(age); this._hobbys = [];}Person.prototype = { //校验函数 checkName:function(name){ re = /\d/; return re.test(name); }, sayName:function(){ console.log(this._name); }, sayAge:function(){ console.log(this._age); }, addHobby:function(hobbys){ this._hobbys = this._hobbys.concat(hobbys); }, getHobby:function(){ return this._hobbys; }, setName:function(name){ if(this.checkName(name)){ throw new Error("名字 "+name+" 不能含有数字"); } this._name = name; }, getName:function(){ return this._name; }, setAge:function(age){ this._age = age || "未设置"; }, getAge:function(){ return this._age; }}var person1 = new Person("Helen","20");person1.addHobby(['sing','drawing']);function record(person){ Interface.ensureImplements(person,People); person.sayName(); console.log(person.getHobby().toString());}record(person1);
실행 결과:
Helen
sing, draw
우선 인터페이스를 사용합니다. 이 코드에서는 People 인터페이스가 정의되어 있고, 사람이 이 인터페이스를 구현하고 있습니다. 주석 내용에 주의하세요. (인터페이스에 대해서는 이 기사 JavaScript Using Interfaces를 참조하십시오.)
두 번째로, 값을 얻고 할당하기 위해 get 메소드와 set 메소드를 사용합니다. 우리는 프로그래머가 set을 통해서만 값을 할당할 수 있다는 데 동의할 수 있습니다. 방법 우리는 정확성을 보장하기 위해 할당된 값을 확인합니다. 그러나 이는 단지 관례일 뿐입니다. 프로그래머는 여전히 person1.name = "123"을 통해 값을 할당하고 내부 속성을 수정할 수 있습니다.
표준화하고 알림 역할을 하기 위해 내부 속성의 이름을 표준화하고 이러한 속성 앞에 **_name**, **_age**와 같은 "_"를 추가합니다. 속성을 직접 수정하려면 person1._name = "123"이라고 써야 합니다. 이는 분명히 의도적인 접근 방식이며, 이는 표준이자 알림 역할을 합니다.
그럼에도 불구하고 이러한 종류의 제한만으로는 person1._name을 통한 수정을 방지할 수 없습니다. 다음 방법을 사용하면 내부 속성을 실제로 사유화할 수 있습니다.
클로저를 통한 캡슐화
// Interface var People = new Interface("People",["setName","getName","setAge","getAge","addHobby","getHobby","sayName","sayAge"]); var Person = function(name,age){ //implement People // 私有变量 var _name,_age,_hobbys = []; this.addHobby = function(hobbys){ _hobbys = _hobbys.concat(hobbys); }, this.getHobby = function(){ return _hobbys; }, this.setName = function(name){ if(this.checkName(name)){ throw new Error("名字 "+name+" 不能含有数字"); } _name = name; }, this.getName = function(){ return _name; }, this.setAge = function(age){ _age = age || "未设置"; }, this.getAge = function(){ return _age; } this.setName(name); this.setAge(age); } Person.prototype = { checkName:function(name){ re = /\d/; return re.test(name); }, sayName:function(){ console.log(this.getName()); }, sayAge:function(){ console.log(this.getAge()); } } var person1 = new Person("Helen","20"); person1.addHobby(['sing','drawing']); function record(person){ Interface.ensureImplements(person,People); person.sayName(); console.log(person.getHobby().toString()); } record(person1);
생성자에서 속성이 이를 사용하지 않으면 해당 속성은 외부에서 접근할 수 없지만 클로저는 속성을 통해 이에 접근할 수 있습니다. 그런 다음 클로저를 통해 속성에 값을 할당하기 위한 유일한 항목을 설정하여 이러한 속성을 엄격하게 확인합니다.
그러나 인스턴스가 생성될 때마다 메서드의 복사본이 생성되고 메모리 지원이 필요하므로 생성자에서 메서드를 정의할 필요가 없는 경우가 많습니다. 위의 기본 캡슐화 방법을 사용해보세요. 비공개 속성에 대한 매우 엄격한 확인 요구 사항이 없으면 클로저 방법을 사용하세요.