In the previous two articles, we introduced the memory model of prototypes in JavaScript and the methods of rewriting prototypes, that is, precautions. After understanding prototypes, we can create JavaScript objects through prototypes. Although the prototype-based creation method can effectively complete encapsulation, there are still some problems.
Creating objects through prototypes will mainly cause two problems:
1. The attribute values of the object cannot be set through the constructor.
2. When there are reference type variables in the attribute, there may be duplication of variable values.
Let’s look at the following example:
function Person(){} Person.prototype = { constructor:Person, name:"Leon", age:22, friends:["Ada","Chris"], say:function(){ console.info(this.name+"["+this.friends+"]"); } }
In the above code, we created a Person class and set it up through prototype overriding Some properties and methods, including a friends property, are an array of reference types. Next, we create the object through the Person class. The code is as follows:
var p1 = new Person(); p1.name = "John"; p1.say(); //控制台输出:Jhon[Ada,Chris]
We created the object p1 through the Person class. You can see that there is no way to set attributes for the object p1 when using the prototype method to create an object. We can only set properties for the object p1. The name attribute of p1 is set only after creation. Then call the say() method of p1, and the console will output Jhon[Ada, Chris]. Everything is still normal up to this point.
If we then add a new friend to object p1, the problem will arise. The code is as follows:
p1.friends.push("Mike"); //为p1增加一个朋友(注意这里是在原型中添加) p1.say();
We add a new friend "Mike" to p1 through the push method of the array. At this time, there is no friends attribute in the object p1's own space, so "Mike" will be added. to the prototype of Person, as shown in the figure below:
Since the newly added array elements are placed in the prototype, all objects created later will share this attribute. If we create object p2 at this time, there will also be a "Mike" among his friends. This is a result we don't want to see.
var p2 = new Person(); //如果p1 push之后,原型中就多了一个人,p2也多了一个朋友 p2.say();
Create objects based on combining prototypes and constructors
In order to solve the above problems, we can create objects based on combining prototypes and constructors. That is, the properties are defined in the constructor and the methods are defined in the prototype. This method effectively combines the advantages of both, and is the most commonly used way to create objects in JavaScript.
function Person(name,age,friends){ //属性在构造函数中定义 this.name = name; this.age = age; this.friends = friends; } Person.prototype = { //方法在原型中定义 constructor:Person, say:function(){ console.info(this.name+"["+this.friends+"]"); } }
All properties of the object created in this way are stored in the object's own space. At this point, when creating the object, we can set its own properties for the object.
var p1 = new Person("Leon",22,["Ada","Chris"]); p1.name = "John"; p1.say(); //控制台输出: John[Ada,Chris]
After completing the above code, the memory model of the Person class and p1 object is as shown below:
At this time, we add another When a new friend is added, it will be added to the friends attribute in the memory space of the p1 object itself. In this way, the properties of each object are independent and will not interfere with each other.
p1.friends.push("Mike"); //为p1增加一个朋友(注意这里是在p1自己的空间中添加) p1.say(); //控制台输出: John[Ada,Chris,Mike] var p2 = new Person(); p2.say(); //控制台输出: John[Ada,Chris]
Therefore, when object p2 is created now, the friends of p2 object will only be "Ada" and "Chris", but not "Mike".
Creating objects using dynamic prototypes
Although it is perfect to create objects based on the combination of prototypes and constructors, there are still some differences between it and the way of creating objects in pure object-oriented languages: Class methods are defined outside the class. In order to make the definition object more in line with the requirements of the object-oriented specification, we can place the prototype code of the definition method in the Person constructor. This method is called dynamic prototyping to create objects.
// 动态原型方式 function Person(name,age,friends){ this.name = name; this.age = age; this.friends = friends; Person.prototype.say = function(){ console.info(this.name+"["+this.friends+"]"); } }
Note that when using dynamic prototypes to create objects, we cannot use prototype rewriting when defining methods. For example, the following code is wrong:
// 错误的动态原型方式 function Person(name,age,friends){ this.name = name; this.age = age; this.friends = friends; //不能使用原型重写的方式来设置方法 Person.prototype = { constructor:Person, say:function(){ console.info(this.name+"["+this.friends+"]"); } } }
Use dynamic Creating objects in the prototype way also has problems, because the methods in the class are created through Person.prototype.say, so every time an object is created, a new say() method will be created in memory. The way to solve this problem is that we can first make a judgment to see if the Person.prototype.say method exists, and create it only if it does not exist, otherwise it will not be created.
// 动态原型方式 function Person(name,age,friends){ this.name = name; this.age = age; this.friends = friends; //判断Person.prototype.say是否存在,不存在就创建 if(!Person.prototype.say){ alert("创建say方法"); Person.prototype.say = function(){ console.info(this.name+"["+this.friends+"]"); } } }
为了验证判断条件是否起作用,我们在代码中的判断分支中添加了一个弹出对话框语句。我们可以创建2个对象,然后2个对象分别调用say()方法,在结果中,第一个对象在调用say()方法时会弹出对话框,而第二个对象在调用say()方法时就不会在弹出对话框了,也就是说创建第二个对象时不会再添加say()方法。
以上就是JavaScript面向对象-基于组合和动态原型创建对象的内容,更多相关内容请关注PHP中文网(www.php.cn)!