Basic encapsulation method
Please see the following example:
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());
Run result:
Jane
sing, drawing
TabWeng
football, study, running
This is mentioned in JavaScript creation object, the properties that can be shared are and methods are written on the prototype, and the properties and methods that require each instance to have its own copy are placed in the constructor.
Now there is a problem. The input name cannot contain numbers. How to solve it? The solution is to write a function that checks the name and write this function on the prototype.
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());
In this code, we wrote a checkName() function to verify the name. For the time being, we just want to verify that there cannot be numbers. Then we will verify it in the first line of code in the constructor. If the verification fails, If passed, an exception is thrown.
Here I passed in a name Helen666, and the following exception was thrown:
Error: The name Helen666 cannot contain numbers
This achieves a basic encapsulation and implements internal verification.
But there is another problem. We can also define the name like this:
var person1 = new Person("Helen","20"); person1.name = "Helen666"; person1.sayName(); //Helen666
The name can still be modified to an illegal name, so we thought of using the get method and the set method for control, and the value can only be assigned through the set method , while verifying through the set method, and obtaining the value through the get method. The current code modification is as follows:
// 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);
Running results:
Helen
sing, drawing
First of all, in this code we use an interface and define the People interface, and person implements this interface. Pay attention to the content of the comments. (For interfaces, please see this article JavaScript uses interfaces)
Secondly, we use the get method and the set method to obtain and assign values. We can agree that programmers can only assign values through set, and in the set method we assign values The values are checked to ensure accuracy. But this is just a convention. Programmers can still assign values and modify internal attributes through person1.name = "123".
In order to standardize and serve as a reminder, we standardize the naming of internal attributes and add "_" in front of these attributes, such as **_name** and **_age**, so that if the programmer wants to modify the attributes directly, Then he must write person1._name = "123" like this. This is obviously a deliberate approach. Most programmers will not do this, and it serves as a standard and reminder.
Despite this, this kind of restriction only by regulations cannot prevent modification through person1._name. The following method can truly privatize the internal attributes.
Encapsulation through closure
// 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);
In the constructor, if the attribute does not use this, the attribute cannot be accessed externally, and the closure can access this attribute through the scope chain, then we set it through the closure The only entry point for assigning values to attributes, thereby strictly verifying these attributes.
However, it is often unnecessary to define methods in the constructor, because every time an instance is created, a copy of the method will be generated, which requires memory support, so during use, if it can be used Use the above basic encapsulation method as much as possible. Unless there are very strict verification requirements for private attributes, use closure.